Last active
January 7, 2025 13:54
-
-
Save kjunichi/a6143859f906830bf6bb47eaecdfbdc9 to your computer and use it in GitHub Desktop.
webサーバーから日本語フォントのレンダリング情報をJSONでもらってArduino UNO R4 LEDに表示する
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { createCanvas, Image, registerFont } = require('canvas') | |
const { serve } = require(`@hono/node-server`) | |
const { Hono } = require('hono') | |
const app = new Hono() | |
app.get('/', (c) => { | |
return c.text('Hello Hono!') | |
}) | |
const getJson = (data) => { | |
} | |
const genFontData = async (cs, moji, callback) => { | |
const target = moji | |
const fsize = 8 | |
cs.width = fsize | |
cs.height = fsize //+ 2 | |
const ctx = cs.getContext("2d") | |
//ctx.font = `${fsize}px "UD Digi Kyokasho N-R"` | |
ctx.font = `${fsize}px "Misaki"` | |
//ctx.font = `${fsize}px "MS Pゴシック"` | |
ctx.textBaseline = "bottom" | |
ctx.fillText(target, 0, fsize + 1); | |
const arraySize = cs.width * cs.height * 4 | |
//console.log(`w = ${cs.width}, h = ${cs.height}`) | |
const simg = ctx.getImageData(0, 0, cs.width, cs.height) | |
const img = new Image() | |
const cs2 = createCanvas(400, 400) | |
cs2.width = cs.width * 4 | |
cs2.height = cs.height * 4 | |
const ctx2 = cs2.getContext("2d") | |
const out = { "value": "" } | |
await new Promise((resolve) => { | |
img.onload = async () => { | |
//console.dir(`img = ${img}`) | |
ctx2.drawImage(img, 0, 0, cs2.width, cs2.height) | |
const limage = ctx.getImageData(0, 0, cs.width, cs.height) | |
let pidx = 0 | |
//console.log(`${cs.width},${cs.height}`) | |
let buf = [] | |
for (let y = 0; y < cs.height; y++) { | |
let line = "" | |
for (let x = 0; x < cs.width; x++) { | |
if (limage.data[pidx + 3] > 100) { | |
line += "1" | |
} else { | |
line += "0" | |
} | |
pidx += 4 | |
} | |
console.log(`${line}`) | |
buf.push(line + "0000") | |
} | |
out.value = buf.length + "\n" | |
out.line = buf.join("") | |
resolve(out.line); | |
} | |
img.src = cs.toDataURL("image/png"); | |
}) | |
return out.line | |
} | |
app.get('/moji', async (c) => { | |
const mojiRetsu = c.req.query('m') | |
console.log(`mojiRetsu = ${mojiRetsu}`) | |
const len = mojiRetsu.length | |
let counter = 0 | |
let matData = [] | |
const cb = (data) => { | |
console.log(`cb start data = ${data}`) | |
counter = counter + 1 | |
matData.push(data) | |
console.log(`counter = ${counter}, len = ${len}`) | |
} | |
for (const moji of mojiRetsu) { | |
// dataに0,1で96ビット分が帰ってくる | |
const data = await genFontData(cs, moji, null) | |
//console.log(data.split('')) | |
let frame = [] | |
for(let i= 0; i< 3; i++) { | |
let tmpline=[] | |
for(let j= 0; j< 32; j++) { | |
tmpline.push(data[i*32+j]) | |
} | |
tmpline = tmpline.join("") | |
tmphex = parseInt(tmpline,2).toString(16) | |
console.log(`tmpline = 0x${tmphex}`) | |
frame.push(parseInt(tmpline,2)) | |
} | |
// dataから32ビット区切りで16進数にする | |
matData.push({"frame": frame}) | |
} | |
return c.json(matData) | |
}) | |
const port = 3000 | |
console.log(`Server is running on http://localhost:${port}`) | |
registerFont('misaki_gothic.ttf', { family: 'Misaki' }) | |
const cs = createCanvas(400, 400) | |
serve({ | |
fetch: app.fetch, | |
port | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//kjunichi | |
#include <WiFiS3.h> | |
#include <Arduino_LED_Matrix.h> | |
#include <UrlEncode.h> | |
#include <ArduinoJson.h> | |
#include "arduino_secrets.h" | |
#include "anim.h" | |
///////please enter your sensitive data in the Secret tab/arduino_secrets.h | |
char ssid[] = SECRET_SSID; // your network SSID (name) | |
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) | |
// grid dimensions. should not be larger than 8x8 | |
#define MAX_Y 8 | |
#define MAX_X 12 | |
#include <LiquidCrystal.h> | |
unsigned long blankFrame[] = { 0, 0, 0 }; | |
unsigned long gFrames[100][3]; | |
unsigned long line[8]; | |
int gNumFrames = 0; | |
int numFrames = 0; | |
int idxInFrame = 0; | |
ArduinoLEDMatrix matrix; | |
int tempPin = 0; | |
int status = WL_IDLE_STATUS; | |
WiFiServer wifiServer(80); | |
WiFiClient client; | |
//char server[] = "DESKTOP-F4B6ASC.local"; | |
char server[] = "192.168.0.15"; | |
int port = 3030; | |
// BS E D4 D5 D6 D7 | |
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); | |
// display the current grid to the LED matrix | |
void displayGrid() { | |
// 現在のフレームを1ドット左にずらす | |
// 96/32 => 12x8 | |
line[0] = (blankFrame[0] & 0b11111111111100000000000000000000) >> 20; | |
line[1] = (blankFrame[0] & 0b00000000000011111111111100000000) >> 8; | |
line[2] = ((blankFrame[0] & 0b00000000000000000000000011111111) << 4) | ((blankFrame[1] & 0b11110000000000000000000000000000) >> 28); | |
line[3] = (blankFrame[1] & 0b00001111111111110000000000000000) >> 16; | |
line[4] = (blankFrame[1] & 0b00000000000000001111111111110000) >> 4; | |
line[5] = ((blankFrame[1] & 0b00000000000000000000000000001111) << 8) | ((blankFrame[2] & 0b11111111000000000000000000000000) >> 24); | |
line[6] = (blankFrame[2] & 0b00000000111111111111000000000000) >> 12; | |
line[7] = (blankFrame[2] & 0b00000000000000000000111111111111); | |
for (int i = 0; i < 8; i++) { | |
line[i] = line[i] << 1; | |
} | |
//Serial.println(gFrames[numFrames][0], BIN); | |
line[0] = line[0] | (((gFrames[numFrames][0] >> 20) & 0b111111111111) >> (8 - idxInFrame) & 0b1); | |
line[1] = line[1] | (((gFrames[numFrames][0] >> 8) & 0b111111111111) >> (8 - idxInFrame) & 0b01); | |
line[2] = line[2] | ((((gFrames[numFrames][0] << 4) & 0b111111110000) | ((gFrames[numFrames][1] >> 28) & 0b000000001111)) >> (8 - idxInFrame) & 0b01); | |
line[3] = line[3] | (((gFrames[numFrames][1] >> 16) & 0b111111111111) >> (8 - idxInFrame) & 0b1); | |
line[4] = line[4] | (((gFrames[numFrames][1] >> 4) & 0b111111111111) >> (8 - idxInFrame) & 0b1); | |
line[5] = line[5] | (((gFrames[numFrames][1] << 8) & 0b111100000000) | ((gFrames[numFrames][2] >> 24) & 0b000011111111) >> (8 - idxInFrame) & 0b1); | |
line[6] = line[6] | (((gFrames[numFrames][2] >> 12) & 0b111111111111) >> (8 - idxInFrame) & 0b1); | |
line[7] = line[7] | ((gFrames[numFrames][2] & 0b111111111111) >> (8 - idxInFrame) & 0b1); | |
blankFrame[0] = ((line[0] << 20) & 0b11111111111100000000000000000000) | ((line[1] << 8) & 0b00000000000011111111111100000000) | (line[2] >> 4) & 0b00000000000000000000000011111111; | |
blankFrame[1] = ((line[2] << 28) & 0b11110000000000000000000000000000) | ((line[3] << 16) & 0b00001111111111110000000000000000) | ((line[4] << 4) & 0b00000000000000001111111111110000) | ((line[5] >> 8) & 0b00000000000000000000000000001111); | |
blankFrame[2] = (((line[5] << 24) & 0b11111111000000000000000000000000) | ((line[6] << 12) & 0b00000000111111111111000000000000) | (line[7] & 0b00000000000000000000111111111111)); | |
if (idxInFrame < 8) { | |
idxInFrame++; | |
} else { | |
idxInFrame = 0; | |
numFrames++; | |
} | |
//matrix.loadFrame(gFrames[numFrames]); | |
matrix.loadFrame(blankFrame); | |
if (numFrames >= gNumFrames) { | |
numFrames = 0; | |
} | |
} | |
void getMatData() { | |
if (client.connect(server, port)) { | |
char sbuf[1024]; | |
String query; | |
query = urlEncode("日本語文字列のテスト!(aplphabet)"); | |
//Serial.println(query); | |
sprintf(sbuf, "GET /moji?m=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", query.c_str(), server); | |
Serial.print(sbuf); | |
client.print(sbuf); | |
memset(sbuf, 0x00, sizeof(sbuf)); | |
delay(1000); | |
while (true) { | |
read_response(sbuf); | |
break; | |
} | |
} else { | |
Serial.println("Oops! server"); | |
} | |
} | |
void read_response(char *buf) { | |
while (client.available()) { | |
char c = client.read(); | |
strncat(buf, &c, 1); | |
} | |
Serial.print(buf); | |
// Check HTTP status | |
char *p = strtok(buf, "\r\n"); | |
Serial.println(p); | |
if (strncmp(p, "HTTP/1.1 200 OK", 15) != 0) { | |
Serial.print(F("Unexpected response: ")); | |
Serial.println(p); | |
client.stop(); | |
return; | |
} | |
Serial.println("HTTP Status check is OK."); | |
// Skip HTTP headers | |
while ((p = strtok(NULL, "\r")) != NULL) { | |
Serial.print(p); | |
if (strcmp(p, "\n") == 0) { | |
Serial.println("End of Http Headers"); | |
break; | |
} | |
} | |
p = strtok(NULL, "\r\n"); | |
DynamicJsonDocument doc(4096); | |
// Parse JSON object | |
DeserializationError error = deserializeJson(doc, p); | |
if (error) { | |
Serial.print(F("deserializeJson() failed: ")); | |
Serial.println(error.f_str()); | |
client.stop(); | |
return; | |
} | |
JsonArray array = doc.as<JsonArray>(); | |
for (JsonVariant v : array) { | |
JsonObject jsonObj = v.as<JsonObject>(); | |
unsigned long frame[3]; | |
JsonArray frameArray = jsonObj["frame"].as<JsonArray>(); | |
int idx = 0; | |
for (JsonVariant v2 : frameArray) { | |
Serial.println(v2.as<unsigned long>()); | |
gFrames[gNumFrames][idx] = v2.as<unsigned long>(); | |
frame[idx++] = v2.as<unsigned long>(); | |
} | |
gNumFrames++; | |
matrix.loadFrame(frame); | |
delay(400); | |
} | |
} | |
void setup() { | |
Serial.begin(115200); | |
lcd.begin(16, 2); | |
matrix.begin(); | |
// check for the WiFi module: | |
if (WiFi.status() == WL_NO_MODULE) { | |
Serial.println("Communication with WiFi module failed!"); | |
// don't continue | |
while (true) | |
; | |
} | |
String fv = WiFi.firmwareVersion(); | |
if (fv < WIFI_FIRMWARE_LATEST_VERSION) { | |
Serial.println("Please upgrade the firmware"); | |
} | |
// attempt to connect to WiFi network: | |
while (status != WL_CONNECTED) { | |
Serial.print("Attempting to connect to SSID: "); | |
Serial.println(ssid); | |
// Connect to WPA/WPA2 network. Change this line if using open or WEP network: | |
status = WiFi.begin(ssid, pass); | |
// wait 10 seconds for connection: | |
delay(10000); | |
} | |
wifiServer.begin(); | |
// you're connected now, so print out the status: | |
printWifiStatus(); | |
getMatData(); | |
} | |
void proc_webserver() { | |
} | |
int cnt = 0; | |
void loop() { | |
//read_response(); | |
int tempReading = analogRead(tempPin); | |
// This is OK | |
double tempK = log(10000.0 * ((1024.0 / tempReading - 1))); | |
tempK = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * tempK * tempK)) * tempK); // Temp Kelvin | |
float tempC = tempK - 273.15; // Convert Kelvin to Celcius | |
float tempF = (tempC * 9.0) / 5.0 + 32.0; // Convert Celcius to Fahrenheit | |
/* replaced | |
float tempVolts = tempReading * 5.0 / 1024.0; | |
float tempC = (tempVolts - 0.5) * 10.0; | |
float tempF = tempC * 9.0 / 5.0 + 32.0; | |
*/ | |
// Display Temperature in C | |
lcd.setCursor(0, 0); | |
lcd.print("Temp C "); | |
// Display Temperature in F | |
//lcd.print("Temp F "); | |
lcd.setCursor(6, 0); | |
// Display Temperature in C | |
lcd.print(tempC); | |
lcd.setCursor(0, 1); | |
lcd.print("@kjunichi"); | |
lcd.setCursor(11, 1); | |
lcd.print(tempReading); | |
// Display Temperature in F | |
//lcd.print(tempF); | |
//Serial.println(tempC); | |
//matrix.loadFrame(animation[(cnt+tempReading)%5]); | |
cnt++; | |
displayGrid(); | |
delay(100); | |
} | |
void printWifiStatus() { | |
// print the SSID of the network you're attached to: | |
Serial.print("SSID: "); | |
Serial.println(WiFi.SSID()); | |
// print your board's IP address: | |
IPAddress ip = WiFi.localIP(); | |
Serial.print("IP Address: "); | |
Serial.println(ip); | |
// print the received signal strength: | |
long rssi = WiFi.RSSI(); | |
Serial.print("signal strength (RSSI):"); | |
Serial.print(rssi); | |
Serial.println(" dBm"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment