ベートーベン・チャネルとは言ってますが、正確にはベートーベン同時代古典派の作曲家の曲を流すと言った方が正確でしょう。間違ってもロマン派とかイタリア、ロシアの作曲家の曲は流れてきません。
MozartやHydnも流れてきますが、画像にあるようにオランダオーケストラの曲で時々のアナウンスでもNetherlandからと言ってます。おおむねどこのラジオ局でもラジオ局が属する国の楽団の演奏を流すのは、自国の文化の宣伝という意味のほかに著作権料でも優遇されるからなのかも知れません。
admin

la vie libre
Nodeに関連して検索したサイトと自分用のメモです。
○ WebSocketのURL形式
通信時に指定するURLは、
ws://www.sample.com、あるいはセキュア接続ならwas://www.sample.com
明に使うことはあまりないだろうけども
○ Node.jsでソケット通信
<socket.ioのインストール>(アプリを作成するディレクトリで)
% npm install socket.io
もはやdgramはインストール不要らしい
○ websocket動かすには
Node.jsとExpressの他にwsライブラリのインストールも必要、本当?
<HTTP serverとclientサンプル>
socket.ioを使った、
以下の二つはGitHubのサンプル動かしているのでセット
https://qiita.com/kouji0705/items/cf16044c7d825d09d707
https://github.com/neroneroffy/webSocketDemo
https://ai-soldier.work/websocket-node-ws/#
これ動かしてみたけど、ラズパイでも軽快に動く
○ Express
<documents>
<解説>
https://qiita.com/mml/items/3cc90479df033c0998e4
https://qiita.com/ganyariya/items/85e51e718e56e7d128b8
<起動>
$ npm start
○ pug(HTMLテンプレート)について
<pugの概要>
https://and-ha.com/coding/what-is-pug/
こんなこともできる(markdownをincludeしてHTML出力)
https://ytyaru.hatenablog.com/entry/2018/05/01/000000
<pugの拡張>
https://qiita.com/zenno04/items/d16f881170170b567b16
Template Inheritance
https://pugjs.org/language/inheritance.html
○ wsサーバーの起動
Express serverとWebSocket severそれぞれ別に起動で良い
$ node ws_server.js
実際の運用は起動スクリプトに書くから個別起動で問題ない
○ Javascript(chart.js)でグラフ作成
json使いましょう
https://www.web-development-kb-ja.site/ja/javascript/chartjsでjsonデータを表示する/833307193/
○ JSからEJSへ
use strict : ESM(ES module)有効なら指定不要だったよね
admin
https://isehara-3lv.sakura.ne.jp/blog/2022/11/29/ラズパイでwebsocket通信(その2)/
の続編で、
① M5stackからラズパイにUDPでデータ送信して、
② ラズパイとクライアント間でweb_socket使ってリアルタイムのデータ更新(今は5秒毎にM5stackから送信)、
③ 受信データをchart.js使ってグラフ化(データ最大5回分)、
します。
WebSocketで送られるデータ形式は汎用性考慮してjson形式を使っています。
全体のコードは、
M5stack側、
https://github.com/chateight/multi_sensor_udp_comm
ラズパイ側、
https://github.com/chateight/web_socket
となります。現状、測定値を送信するのはthermo_sensorのコードだけですが、他のセンサーでも同じルーチン(udp_loop(String))呼び出せば送信できます。
web_socketはセッションが有効な時しか働かないので、セッションが切れればデータは更新されません。
ブラウザ画面の表示はこちらを、
admin
これもネットラジオ曲ですが、イギリスからの高音質(320Kbps)のラジオ。
しばらく中断していましたが、再開されてます。
広告なしでどうやって運営してるのかは気になるところ、オペーレーティング費用の他に著作権料の支払いも必要なわけだし。ドネーションだけで全て賄ってる?
無料のspotifyは音質イマイチで広告入るから最近あまり使わない。サブスクするまでも無さそうだし、
admin
の続編です。
Expressのプロジェクトのviews以下に以下のファイルを配置しました。pugファイルの継承機能の確認も兼ねています。block inheriの直下にblock contentがあるので、index.pugの内容が挿入されて結果として作成されるHTMLファイルは複数のpugファイルから構成されます。
layout.pug
--------------
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
<script src="./javascripts/ws_client.js" defer>
body
block inheri<
inheri.pug
--------------
extends layout
block inheri
block content
p Test site for M5stack data transfer using UDP & WebSocket
p#message.poor-writing ws test button
<input type="button" id="send_server" value="send" />
<div id="mes">web socket out put area</div>
index.pug
--------------
extends inheri
block content
h1= title
p #{title} is provided for timely data access
p ----------------------------------------------
クライアント側で動作するws_client.jsとサーバー側で動作するws_server.jsスクリプトです。いずれもpublic/javascriptsに配置してます。
ブラウザ上のbuttonを押すとサーバー側ではws_server.jsが検出して、サーバー側からレスポンスを返しています。
ws_client.js
--------------
const ws = new WebSocket('ws://raspberrypi.local:3002')
ws.onopen = e => {
console.log('Hello M5 server!')
}
ws.onmessage = e => {
const mes = document.querySelector("#mes");
mes.textContent = e.data;
console.log('received data:%s',e.data)
console.log(e)
}
ws.onerror = e => {
console.log('fail to connect:${e.data}')
console.log(e)
}
document.getElementById('send_server').addEventListener('click', () => {
ws.send('call back from the button')
})
ws_server.js
--------------
const WebSocketServer = require('ws').Server;
const wss = new WebSocketServer({ port: 3002 });
wss.on('connection', ws_client => {
ws_client.send('good morning');
ws_client.on('message', data => {
console.log('send data: %s', data);
ws_client.send('received the data:' + data);
});
});<起動>
Express:
$ npm start
WS:
$ node ws_server.js
別々に起動してもいいけど、おそらくExpress側で起動する様にできるはず。
以下の画面操作の動画です。
参考サイトは、
pugの継承
https://qiita.com/zenno04/items/d16f881170170b567b16
簡単ws使い方
https://ai-soldier.work/websocket-node-ws/
次にやりたいことはM5stackと以下のようにつなぐこと、Port 3000は共通ですが、UDPとTCP/IPの違いなので問題ありません。
admin
M5stackをIoT端末として使うときにサーバー(この場合はラズパイ)にメッセージを送る必要がありますが、Wi-Fiが一番汎用性がありそう。
というわけで、UDP使ってメッセージを送ってみます。ラズパイ側はサーバーにNode.js使うので同じくNode.jsスタイルで記述します。
<M5stack側>
NTPサーバー使って現在時刻の取得、mDNS機能を使ってラズパイのアドレスを検索しています。参考サイトは、以下の通りです。
・タイムサーバーの使い方
https://kuracux.hatenablog.jp/entry/2018/10/08/160000
・IPアドレスを4オクテット記法に変換する
https://qiita.com/dojyorin/items/ac56a1c2c620782d90a6
#include <m5stack.h>
#include <WiFi.h>
#include <wifiudp.h>
#include <espmdns.h>
// Wi-Fi connection info.
const char* ssid = "your said";
const char* password = "your pw";
const int port = 3002;
String string_buf = "message from M5stack";
//ntp server and time info
const char* ntpServer = "ntp.nict.jp";
const long gmtOffset_sec = 9 * 3600;
const int daylightOffset_sec = 0;
struct tm timeinfo;
// The udp library class
WiFiUDP udp;
// mDNS target & M5stack
const String target_dev = "raspberrypi";
IPAddress ip; // IPAdress of the target device
String ip_addr = ""; // 4 octet style target address
const char *mdns_name = "m5stick"; //M5stack mDNS name
// convert IP address to 4 octet style
String ipToString(uint32_t ip){
String result = "";
result += String((ip & 0xFF), 10); // base number : 10
result += ".";
result += String((ip & 0xFF00) >> 8, 10);
result += ".";
result += String((ip & 0xFF0000) >> 16, 10);
result += ".";
result += String((ip & 0xFF000000) >> 24, 10);
return result;
}
void mdns(){
mdns_init();
ip = MDNS.queryHost(target_dev);
// target dev IP
Serial.println("");
Serial.print(target_dev + " : ");
Serial.println(ip);
// M5 self IP
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
ip_addr = ipToString(ip);
// register mDNS name
if (MDNS.begin(mdns_name)) {
Serial.println("MDNS responder started");
}
}
void print_wifi_state(){
M5.Lcd.clear(BLACK); // clear LCD
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.setCursor(3, 3);
M5.Lcd.println("");
M5.Lcd.println("WiFi connected.");
M5.Lcd.print("IP address: ");
M5.Lcd.println(WiFi.localIP());
M5.Lcd.print("Port: ");
M5.Lcd.println(port);
}
void setup_wifi(){
M5.Lcd.setTextColor(RED);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(3, 10);
M5.Lcd.print("Connecting to ");
M5.Lcd.println(ssid);
// setup wifi
WiFi.mode(WIFI_STA); // WIFI_AP, WIFI_STA, WIFI_AP_STA or WIFI_OFF
WiFi.begin(ssid, password);
// WiFi.begin();
// Connecting ..
while (WiFi.status() != WL_CONNECTED) {
delay(100);
M5.Lcd.print(".");
}
// print state
print_wifi_state();
udp.begin(port);
// mDNS
mdns();
}
void setup() {
M5.begin();
Serial.begin(115200);
// setup wifi
setup_wifi();
//init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
}
void loop(){
// get current rime
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
String cur_time = String(timeinfo.tm_year + 1900)
+ "/" + String(timeinfo.tm_mon)
+ "/" + String(timeinfo.tm_mday)
+ " " + String(timeinfo.tm_hour)
+ ":" + String(timeinfo.tm_min)
+ " " + String(timeinfo.tm_sec) + " ";
Serial.println(cur_time);
//udp send
const char *ipadr = ip_addr.c_str();
udp.beginPacket(ipadr, port);
// current time
int i = 0;
while( cur_time.length() > i){
char tmp = cur_time.charAt(i);
udp.write(tmp);
i++;
}
// contents
i = 0;
while( string_buf.length() > i){
char tmp = string_buf.charAt(i);
udp.write(tmp);
i++;
}
udp.endPacket();
delay(1000);
}
<ラズパイ側>
Node.js配下のスクリプトです。
const dgram = require('dgram');
const port = 3002;
const client ='0.0.0.0';
const socket = dgram.createSocket('udp4');
socket.bind(port, client);
socket.on('message', (message, remote) => {
console.log(remote.address + ':' + remote.port +' - ' + message);
});参考サイトは、
・ラズパイのavahiユティリティのインストールと使い方
$ sudo apt-get install avahi-utils
Wi-Fi内のデバイスリスト
$ avahi-browse -at
・Node.jsのUDP通信ドキュメント
https://runebook.dev/ja/docs/node/dgram
・what’s socket.io
ラズパイ側の出力、
admin
何かの拍子、おそらく異なるラズパイにログインした時とか、に出るsshログインできない現象。
解決策は、
% rm ~/.ssh/known_hosts
% ssh pi@raspberrypi.local
The authenticity of host 'raspberrypi.local (240d:1a:896:8300:acf1:ba5:2b9e:7977)' can't be established.
ED25519 key fingerprint is SHA256:JkCfuJ3qZs3XON3vOOkf2M7RP5HAXNWwSxAnNG0dqck.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'raspberrypi.local' (ED25519) to the list of known hosts.このように、known_hostsを削除することによって、sshログインが可能となります。
admin
センサーシリーズの第三段目の赤外線温度センサー。この際、センサー種類を切り替える都度ソフトダウンロードが面倒なので、複数のセンサー(今現在、レーザー距離計、熱中症アラームセンサーと赤外線温度センサー)に対応できるようにコードを書き換え。
具体的にはsetup()処理の中で、センサーの初期化コマンドを出して正常にレスポンスが返って来たものをターゲットにして、loop()処理中で呼び出す処理を振り分けします。以下はsetup()処理だけ切り出し、
void setup(void)
{
M5.begin(); // Init M5Stack
M5.Power.begin(); // Init power
Wire.begin(); // Wire init, adding the I2C bus.
Serial.begin(115200);
if (setup_dist() == 1){
dev_id = 1;
} else if (setup_env() == 1){
dev_id = 2;
} else if (setup_thermo() == 1){
dev_id = 3;
}
else{
while(1){
sensor_error();
delay(1000);
}
}
}温度センサーはライブラリ、
https://github.com/adafruit/Adafruit-MLX90614-Library
をダウンロードして使用。
使ってみた感じは、非接触ではあるけれどもターゲットにかなり近寄らないときちんとした値が取れないようです。
————————
P.S. 2022/11/24
MLX90614には視野角で何種類かあって、このモデルはおよそ90度なのでその視界に入るオブジェクトの平均値が表示されるからです。
————————
こんな感じに、
全体のコードは以下のリンクで、
https://github.com/chateight/multi_sensor_hdl
admin
M5stackでビルドした時に必要メモリサイズが出力されますが、なぜか搭載メモリ(Flash)サイズに比較してずいぶん小さい。
やりたいことは色々なセンサーの種類をsetup()ルーチン中で判別して必要なコードにloop()から呼び出しをするということなので、センサーの種類が増えていくとメモリをどんどん消費していくから。
写真の場合にはmDNSを使おうとした場合ですが、ライブラリのサイズが大きいようで既に6割以上を消費しています。
実際のメモリは16MB搭載しているはずですが、1.3MBぐらいしか使えないことになっています。もちろん基本のファームウェア領域も存在するんだろうけど、それにしては少なすぎ。
これを拡張するには、ボードの種類をM5Stack-Core-ESP32からM5Stack-fireにすると拡大します。ただしこれでも見えるサイズは6.5MBぐらいなので搭載メモリの半分以下ですが、5倍に拡大されたと思えば大幅改善で、さらにRAM領域はおよそ10倍に拡張されているので、おそらくRAM領域は不足するような事態には特別にRAM領域を消費するようなコードを書かない限りは大丈夫そうです。
ボード種類を変えることによる副作用は今のところ見えていません。このやり方はArduino IDEに限らずVScodeのPlatformIOでも同じです。
M5stackでもコードは起動後は不変だからFlash領域を使用して、変数やスタック領域などの書き換え必要な領域にはRAM領域を使用するようになっています。
admin