うち、やっぱ、Scratch Remote Sensorが、むっちゃ好っきゃねん
https://gyazo.com/155b0938fb0bbe6eaec3ec0227ee6d5a
https://gyazo.com/bc22e40dda93d3625ada0b7480ea4b40
むとうたけしって?
主夫@奈良
Twitter: @610t / Scratch ID: 610t CoderDojo奈良 メンター
関西 *BSDユーザ会メンバー
FreeBSD lang/squeak メンテナー
Arduino(ESP8266), Raspberry Pi, micro:bit, 付録基板などなどの類が好き
https://gyazo.com/1f2d2e487865fe8e17887defb13f81bc
Scratchと拡張機能
Javascriptで書いたExtensionをScratchXから使う
外部ハードウエアなどを扱える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側では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に送る一方向
iOSにもある?
ESP8266ってなぁに?
無線LANが使える Arduino
Arduino IDEで開発 (C,C++)
WeMos D1 mini: 小型(34.2 x 25.6mm, 3g)のESP8266デバイス スタックできるセンサー/アクチュエーターシールドあり https://gyazo.com/cb6d3286840d1e1ccb68720e190152f8
WeMos改 x Scratch Remote Sensor
むとうのやったこと
上記のプログラムをWeMosのシールド(ボタン, DHT, RGB LED)が使えるように改造
https://gyazo.com/e4f00b64540f0b26ffc7367bdba0847f
システム構成
https://gyazo.com/155b0938fb0bbe6eaec3ec0227ee6d5a
プログラム例
code:ScratchSensorBoard_ESP8266.ino
/*
Scratch remote sensor protocol
You need to get ssid , password and host
*/
/*
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:
*/
/*
Sensors & Actuators
D2(GPIO4): RGB LED
D3(GPIO0): Button switch
D4(GPIO2): DHT sensor (DHT11), Built-in LED
*/
// Edit these 3 lines:
const char* ssid = "PUT SSID HERE";
const char* password = "PUT PWD HERE";
const char* host = "PUT PC IP ADDRESS HERE";
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, RGBLEDPIN, NEO_GRB + NEO_KHZ800);
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() {
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);
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
}
}
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++) {
}
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 ) {
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++) {
}
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 ) {
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++) {
}
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を使ったこんな構成もできます
https://gyazo.com/223e342215f5047e87f50b743c18de01
おわりに
やっぱり、Scratch Remote Sensorは楽しいです!!
Scratch Remote Sensor is still alive!!
and, Scratch 1.4!!
うち、やっぱ、Scratch Remote Sensorが、むっちゃ好っきゃねん