うち、やっぱ、Scratch Remote Sensorが、むっちゃ好っきゃねん
https://gyazo.com/155b0938fb0bbe6eaec3ec0227ee6d5a
https://gyazo.com/bc22e40dda93d3625ada0b7480ea4b40
2018年8月15日(水) Scratchers Meetup 関西 夜の部 LT
むとうたけし@/CoderDojoNara/CoderDojo奈良, 関西*BSDユーザ会 (610t)
むとうたけしって?
主夫@奈良
Twitter: @610t / Scratch ID: 610t
CoderDojo奈良 メンター
関西 *BSDユーザ会メンバー
FreeBSD lang/squeak メンテナー
ports/216811 New port lang/scratch: block based programing language using for educational purpose
Arduino(ESP8266), Raspberry Pi, micro:bit, 付録基板などなどの類が好き
https://gyazo.com/1f2d2e487865fe8e17887defb13f81bc
Scratchと拡張機能
Scratch 1.4: Remote Sensors Protocol (今回のテーマ)
Scratch 2.0 Extension
Javascript Extension for ScratchX
Javascriptで書いたExtensionをScratchXから使う
HTTP Extension for Offline Editor
外部ハードウエアなどを扱えるhttpサーバを起動して、そこへScratchからアクセスする
Scratch 3.0 拡張機能
Scratch 2.0のJavascript Extensionと基本的には同じ?
なぜ、いまさら、Scratch Remote Sensor?
ネットワークが繋がれば使えるシンプルさ
Scratchから自然に使える
Scratch 1.4 という last resort
オフラインで動作する環境
Squeak/Smalltalkでの魔改造
FreeBSDで使える
なぜ、1.4以降使えなくなったのか?
Webブラウザを、任意のポートで待ち受けするサーバとして動かせないから?
Scratch Remote Sensor Protocol
Scratch 1.4で利用可能 (iOSのPyonkeeを含む)
Remote Sensors Protocol at Scratch Wiki
Scratch(スクラッチ)を外部のプログラムなどとつなぐ「遠隔センサー接続」を解説する by jishiha
おまけ: むとうの古い発表 Scratch1.4をBSDで使ってみるために, Scratch遠隔センサーとESP8266
Scratch側ではTCP 42001で待ち受け
パケットは4byteのパケット長(size)と、パケット長の大きさのメッセージ(msg)
<size: 4 bytes><msg: size bytes>
2種類のメッセージ
broadcast "msg"
メッセージmsgを送る
sensor-update "var1" value1 ...
変数var1の値がvalue1に変わったこと、... を通知
メッセージの型
文字列(UTF-8): 1語(cat, mouse-x)、「"」でクオートした複数文字列 ("a four word string", "embedded ""quotation marks"" are doubled")
数字: 1, -1, 3.14, -1.2, .1, -.2
真偽値(Boolean): true or false
Scratch側の設定
[調べる]カテゴリの <[スライダー▼]センサーの値> を右クリック
[遠隔センサー接続を有効にする] を選択
ネットワーク受信設定が必要な場合は、TCP42001への接続を許可する
Androidで簡単に試す
https://gyazo.com/65c930e719ea8984928657277933b25c
AndroidでScratch Remote Sensorを使うアプリにはいくつかある
Androidのセンサーの値をScratchに送る一方向
Physical Sensor for Scratch
Scratch Sensor (ソース): ScratchX用もある
iOSにもある?
ScratchControler
ESP8266ってなぁに?
無線LANが使える Arduino
Arduino IDEで開発 (C,C++)
ESPr® Developer(ESP-WROOM-02開発ボード) 1944円 など各種
ESP8266ボードWeMos
WeMos D1 mini: 小型(34.2 x 25.6mm, 3g)のESP8266デバイス
スタックできるセンサー/アクチュエーターシールドあり
むとう手持ち: 1-Button, DHT(温湿度), WS2812B RGB LED, microSD, OLED
https://gyazo.com/cb6d3286840d1e1ccb68720e190152f8
WeMos改 x Scratch Remote Sensor
ScratchからWifiで遠隔操作してみる by ちっちゃいものくらぶ: Scratch Remote Sensor ProtocolでESP8266に繋いだモーターを操作する
むとうのやったこと
上記のプログラムをWeMosのシールド(ボタン, DHT, RGB LED)が使えるように改造
WeMosからESPr® Developer(ESP-WROOM-02開発ボード)に置き換え
https://gyazo.com/e4f00b64540f0b26ffc7367bdba0847f
システム構成
https://gyazo.com/155b0938fb0bbe6eaec3ec0227ee6d5a
プログラム例
code:ScratchSensorBoard_ESP8266.ino
/*
Scratch remote sensor protocol
You need to get ssid , password and host
http://tiisai.dip.jp/?p=3665
*/
/*
Copyright 2016 Takeshi MUTOH
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
This program is demonstration that Scrath Remote Sensor Protocol with ESP8266.
My presentation is below:
http://qml.610t.org/squeak/CodarDojoNara201612.html
*/
/*
Sensors & Actuators
D2(GPIO4): RGB LED
D3(GPIO0): Button switch
D4(GPIO2): DHT sensor (DHT11), Built-in LED
*/
#define RGBLEDPIN 4
#define BUTTONPIN 0
#define DHTPIN 2
// Edit these 3 lines:
const char* ssid = "PUT SSID HERE";
const char* password = "PUT PWD HERE";
const char* host = "PUT PC IP ADDRESS HERE";
#include <ESP8266WiFi.h>
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, RGBLEDPIN, NEO_GRB + NEO_KHZ800);
#include "DHT.h"
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
const int Port = 42001;
int ledOn = false;
int r = 0, g = 0, b = 0;
void setup() {
// Set up I/O mode
pinMode(LED_BUILTIN, OUTPUT);
pinMode(BUTTONPIN, INPUT);
// Initialize Serial
Serial.begin(115200);
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// This initializes the NeoPixel library.
pixels.begin();
// Initialize DHT sensor
dht.begin();
}
int value = 0;
void loop() {
uint8_t buffer128 = {0};
float t, t_old, h, h_old;
delay(5000);
++value;
Serial.print("connecting to ");
Serial.println(host);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, Port)) {
Serial.println("connection failed");
return;
}
Serial.print("create tcp ok\r\n");
char *broadcastcmd = "sensor-update \"v\" 0 ";
for (uint32_t n = 0; n < 100000; n++) {
delay(10);
char scmd32 = {0};
char dhtcmd32 = {0};
int sw, stat;
// Read all from server and print them to Serial
client.setTimeout(100);
uint32_t len = client.readBytes(buffer, sizeof(buffer));
String msg = "";
if (len > 0) {
Serial.print("Received:[");
for (uint32_t i = 0; i < len; i++) {
Serial.print((char)bufferi);
if (i >= 4) { // Skip 4 byte message header
msg += (char)bufferi;
}
}
Serial.print("]\r\n");
// Skip until broadcast or sensor-update
while ((!msg.startsWith("broadcast") && !msg.startsWith("sensor-update")) && msg.length() > 0 )
{
msg.substring(1);
}
if (msg.startsWith("broadcast") == true) {
// message
msg.replace("broadcast ", "");
msg.replace("\"", "");
Serial.print("{broadcast:" + msg + "}");
} else if (msg.startsWith("sensor-update")) {
// value
msg.replace("sensor-update ", "");
msg.replace("\"", "");
msg.trim();
while (msg.length() > 0) {
msg.trim();
switch (msg.charAt(0)) {
case 'r':
msg.replace("r ", "");
r = int(msg.toFloat());
Serial.println("{R:" + String(r) + "}");
break;
case 'g':
msg.replace("g ", "");
g = int(msg.toFloat());
Serial.println("{G:" + String(g) + "}");
break;
case 'b':
msg.replace("b ", "");
b = int(msg.toFloat());
Serial.println("{B:" + String(b) + "}");
break;
}
Serial.println("{{msg:" + msg + "}}");
// Skip var_value
while (msg.charAt(0) != ' ' && msg.length() > 0) {
msg = msg.substring(1);
}
Serial.println("{{msg2:" + msg + "}}");
}
Serial.println("{RGB:(" + String(r) + ", " + String(g) + ", " + String(b) + ")}");
} else {
Serial.println("NOP");
}
}
// RGB LED
pixels.setPixelColor(0, pixels.Color(r, g, b));
pixels.show();
// send broadcast message
if (digitalRead(BUTTONPIN) != sw) {
sw = digitalRead(BUTTONPIN); stat = 1;
strcpy(scmd + 4, "broadcast \"button\"");
} else {
if (stat == 1) {
stat = 0;
if (digitalRead(BUTTONPIN) == LOW) {
strcpy(scmd + 4, "sensor-update \"btn\" 1 ");
} else {
strcpy(scmd + 4, "sensor-update \"btn\" 0 ");
}
}
}
scmd3 = (uint8_t)strlen(scmd + 4);
if (0 != strlen(scmd + 4)) {
for (uint32_t i = 0; i < 4 + strlen(broadcastcmd); i++) {
Serial.print(scmdi);
}
if (client.write((const uint8_t*)scmd, 4 + strlen(scmd + 4))) {
Serial.println("send ok");
} else {
Serial.println("send err");
}
}
// Get DHT data
t = NAN;
h = NAN;
while ( isnan(t) || isnan(h) ) {
t = dht.readTemperature();
h = dht.readHumidity();
}
if ( t != t_old ) {
char t_str10;
dtostrf(t, 4, 2, t_str);
sprintf(dhtcmd + 4, "sensor-update \"t\" %s", t_str);
for (uint32_t i = 0; i < 4 + strlen(broadcastcmd); i++) {
Serial.print(dhtcmdi);
}
dhtcmd3 = (uint8_t)strlen(dhtcmd + 4);
if (client.write((const uint8_t*)dhtcmd, 4 + strlen(dhtcmd + 4))) {
Serial.println("send ok");
} else {
Serial.println("send err");
}
}
if ( h != h_old ) {
char h_str10;
dtostrf(h, 4, 2, h_str);
sprintf(dhtcmd + 4, "sensor-update \"h\" %s", h_str);
for (uint32_t i = 0; i < 4 + strlen(broadcastcmd); i++) {
Serial.print(dhtcmdi);
}
dhtcmd3 = (uint8_t)strlen(dhtcmd + 4);
if (client.write((const uint8_t*)dhtcmd, 4 + strlen(dhtcmd + 4))) {
Serial.println("send ok");
} else {
Serial.println("send err");
}
}
// Store current h & t
h_old = h;
t_old = t;
}
}
micro:bitを使ったこんな構成もできます
プログラムなどの詳細は Scratch1.4をBSDで使ってみるために
https://gyazo.com/223e342215f5047e87f50b743c18de01
おわりに
やっぱり、Scratch Remote Sensorは楽しいです!!
Scratch Remote Sensor is still alive!!
and, Scratch 1.4!!
うち、やっぱ、Scratch Remote Sensorが、むっちゃ好っきゃねん
#Scratch #ESP32 #Android #presen #ESP8266