NumberBankしよっとね
https://gyazo.com/2dc08ddc0c45b129b9ee1fd3508f13bc
2025/01/30: ビジュアルプログラミングIoTLT Vol.19
by むとうたけし(610t)
当日の発表の様子
【爆速レポ】ビジュアルプログラミングIoTLT vol.19 #IoTLT
posfie(togetter):「ビジュアルプログラミングIoTLT vol.19」に関するつぶやきのまとめ
Youtube (38:17-46:30)
https://www.youtube.com/live/DxK7fhCURS4?t=2297s
NumberBank
NumberBank: Scratch間で数字をやり取りする拡張機能
Stretch3やXcratchで利用可能
ソースコード: https://github.com/con3code/numberbank
データストアはFirestore Database
ブロック一覧
https://gyazo.com/ba4a5869357bb1671c7f606f5e793b69
NumberBankの使い方
key(=データベース)を設定する[マスター(key)をセット]ブロック
デフォルトのkeyでも利用可能(遅延が大きい)
登録すると、自分のデータベースも利用可能
登録は https://masterkey-bank.web.app/
詳細はNumberBank用マスターキーの作り方を参照
データ書き込み
[(バンク)の(カード)を(10)にする]ブロックなどを使って、データベースに値を書き込む
データ読み出し
((バンク)の(カード)の値)ブロックを使って特定のデータを読み出す
非同期データ転送(うまくいかない?)
[(バンク)の(カード)の更新確認を(入)にする]ブロックで更新確認を開始する
データが更新されたとき[更新されたとき]にイベントが渡される
2025/01/30現在、[更新された時]イベントブロックは動作していないような気がする
例:数字のやり取り
https://gyazo.com/87a6f81cb43726ea3f28c54485b32545
例:数字データのやり取り
ここで利用したマスターキーkeyはデフォルトで提供されているもの
バンクbank610t、カードcard610tでデータをやり取り
上矢印で乱数をbank610tのcard610tに書き込み
下矢印でbank610tのcard610tから読み込み
https://gyazo.com/5dd650aa5fd22f2d37cb38167bf1d90f
例:位置データの転送と地図の表示
https://gyazo.com/32f482290170817bf0066f628ee5d921
左画面地図の位置(緯度、経度)を右のScratchに転送して、そちらでも地図を表示する
GeoScratchとの合わせ技
デフォルトのkeyは遅延が大きく設定されているので、かなり遅れる
GPS sender code
https://gyazo.com/8948f4697409066facdc28cb948ed7a3
GPS receiver code
https://gyazo.com/96a467a7f34fbb9ce37e1ae1e9c0496b
NumberBankのシステム構成
https://scrapbox.io/files/677a7195ae4e3c07659335df.svg
ScratchとNumberBankは、keyに割り当てられた設定情報をNumberBank and Firebase mapper(仮)から取得してを接続する
自分のデータベースで利用する時には、mapperへの登録作業が必要
登録は https://masterkey-bank.web.app/
詳細はNumberBank用マスターキーの作り方
NumberBankのデータ構造
Secure Hash(SHA256)を多用したデータ構造
bankコレクション
cardコレクション
bankコレクション
ドキュメント名bank_nameのSHA256
これは無くても読み込み可能
code:bank.json
{
'bank_name': bankの名前,
'timestamp': データが入力された時間,
}
https://gyazo.com/86697e706dccbe986b083d5fc6424d0a
cardコレクション
ドキュメント名uni_key: bankの名前とcardの名前の文字列を結合しSHA256を取ったもの
実際の数値データnumberが入っている
code:card.json
{
'number': 実際の数値データ,
'timestamp': データが入力された時間,
'bank_key': bank名のSHA256,
'card_key': card名のSHA256,
'master_key': master_keyから計算されたSHA256(ダミー値でも利用可能だった),
}
https://gyazo.com/280bfe0b6704336db0245e094ffec75a
Scratch外とのデータのやり取り
Firestore Databaseにアクセスできる言語ならなんでも可能
Python, Node.js, Java, C++, Go, ...
データの操作
アクセス用キーファイル: 以下の<何らかの情報>は自分のものに変更してください。
code:secret_key.json
{
"type": "service_account",
"project_id": <Project ID>,
"private_key_id": <Private Key ID>,
"private_key": <Private Key>,
"client_email": <Client Email>,
"client_id": <Client ID>,
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": <Client X509 CERT URL>,
"universe_domain": "googleapis.com"
}
読み出し
cardコレクションから読み出し可能
sha256(uni_key)ドキュメントからデータを読み込む
code:read.py
uni_key= bank_key.strip()+card_key.strip()
uni_sha256=hashlib.sha256(uni_key.encode()).hexdigest()
ref_card = db.collection(u'card').document(uni_sha256)
データは、ref_cardを辞書として扱った時のnumberに入っている
code:read.py
dict=ref_card.get().to_dict()
num=dict'number'
書き込み
適切にデータを設定して書き込み
bankには、以下のデータを書き込む
bank_name: bank_key(文字列)
time_stamp: 現在の時刻(使っていない?)
code:write.py
now=time.time()
# Data
bank_data={
'bank_name':bank_key,
'time_stamp':now,
}
# Write to database
db.collection("bank").document(bank_sha256).set(bank_data)
card(uni_keyのSHA256(uni_sha256))には、以下のデータを書き込む
number: 実際の数字データ
time_stamp: 現在の時刻(使っていない?)
bank_key: bank_keyのSHA256(bank_sha256)
card_key: card_keyのSHA256(card_sha256)
master_key: ダミーで大丈夫
code:write.py
# Keys & timestamp
bank_sha256=hashlib.sha256(bank_key.encode()).hexdigest()
card_sha256=hashlib.sha256(card_key.encode()).hexdigest()
uni_key= bank_key.strip()+card_key.strip()
uni_sha256=hashlib.sha256(uni_key.encode()).hexdigest()
now=time.time()
# Random data
num=random.randrange(9999)
# Data
card_data={
'number':num,
'time_stamp':now,
'bank_key':bank_sha256,
'card_key':card_sha256,
'master_key': 'dummy',
}
# Write to database
db.collection("card").document(uni_sha256).set(card_data)
例:外部との数字のやり取り
https://gyazo.com/aea6ea34c3d676111df59d5e195624ea
数字読み込みスクリプトread.pyでは、argv[1]にbankの名前を、argv[2]にcardの名前を指定する
$ python read.py bank610t card610t
code:read.py
import sys # ARGV
import hashlib # SHA256
# Firebase
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
# Firebase初期化
cred = credentials.Certificate('secret_key.json')
app = firebase_admin.initialize_app(cred)
db = firestore.client()
# bank名とcard名を取得
bank_key=sys.argv1
card_key=sys.argv2
# アクセス用のSHA256を生成
uni_key= bank_key.strip()+card_key.strip()
uni_sha256=hashlib.sha256(uni_key.encode()).hexdigest()
# データを取得
ref_card = db.collection(u'card').document(uni_sha256)
dict=ref_card.get().to_dict()
num=dict'number'
print(dict)
print("Number:",num)
数字書き込みスクリプトwrite.pyはargv[3]を与えない場合、0-9999の乱数を書き込む
$ python write.py bank610t card610t
$ python write.py bank610t card610t 610
code:write.py
import sys # ARGV
import random # Random data
import hashlib # SHA256
import time # Timestamp
# Firebase
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
# Firebase初期化
cred = credentials.Certificate('secret_key.json')
app = firebase_admin.initialize_app(cred)
db = firestore.client()
# bank名とcard名を取得
bank_key=sys.argv1
card_key=sys.argv2
# 書き込む数字データを用意
print(len(sys.argv))
if(len(sys.argv)>3):
num=int(sys.argv3)
else:
num=random.randrange(9999)
print("Data:", num)
# SHA256ハッシュを計算
bank_sha256=hashlib.sha256(bank_key.encode()).hexdigest()
card_sha256=hashlib.sha256(card_key.encode()).hexdigest()
uni_key= bank_key.strip()+card_key.strip()
uni_sha256=hashlib.sha256(uni_key.encode()).hexdigest()
# bankコレクションを作成
now=time.time()
bank_data={
'bank_name':bank_key,
'time_stamp':now,
}
db.collection("bank").document(bank_sha256).set(bank_data)
# cardコレクションを作成
card_data={
'number':num,
'time_stamp':now,
'bank_key':bank_sha256,
'card_key':card_sha256,
'master_key': 'dummy',
}
db.collection("card").document(uni_sha256).set(card_data)
例:GPSトラッキング
https://scrapbox.io/files/677cbaed0bfad523e5ebdb96.mp4
GPSログデータをScratchのNumberBankとGeo Scratchを使ってトラッキングする。
GPSデータ(SpreM5GPSenseで記録)
code:GPS.csv
日付, 時間, ,緯度 ,北緯 ,経度 ,東経,高度 ,衛星数,HDOP
2025/01/07,00:05:00.08,34.628716,n,135.753555,e,121.800003,4,2.100000
2025/01/07,00:05:00.00,34.628716,n,135.753555,e,121.800003,4,2.100000
2025/01/07,00:05:00.00,34.628738,n,135.753448,e,113.800003,4,2.100000
2025/01/07,00:05:00.00,34.628761,n,135.753479,e,116.099998,4,2.100000
2025/01/07,00:05:00.00,34.628788,n,135.753494,e,116.400002,4,2.100000
コード
code:GPS.py
import sys # ARGV
import hashlib # SHA256
import time # Timestamp
import csv # CSV
# Firebase
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
# Firebase初期化
cred = credentials.Certificate('secret_key.json')
app = firebase_admin.initialize_app(cred)
db = firestore.client()
# bankコレクションGPS設定
bank_key="GPS"
bank_sha256=hashlib.sha256(bank_key.encode()).hexdigest()
now=time.time()
bank_data={
'bank_name':bank_key,
'time_stamp':now,
}
db.collection("bank").document(bank_sha256).set(bank_data)
# cardドキュメント送信用関数
def send_data(card,num):
print(card,num)
now=time.time()
# card
card_sha256=hashlib.sha256(card.encode()).hexdigest()
card_data={
'bank_key':bank_sha256,
'card_key':card_sha256,
'master_key': 'dummy',
'number':num,
'time_stamp':now,
}
uni_key=bank_key.strip()+card.strip()
uni_sha256=hashlib.sha256(uni_key.encode()).hexdigest()
db.collection("card").document(uni_sha256).set(card_data)
with open("GPS.csv") as f:
reader = csv.reader(f)
for row in reader:
send_data("Lat", row2) # 緯度
send_data("Lon", row4) # 経度
time.sleep(1)
例:外部との文字列のやり取り
https://gyazo.com/0ba3dc178ff8498116bb274185bc6f4b
card名str{数字}にtableリストで定義した独自文字コードを一文字づつ入れる
Python -> Scratch
code:send_str.py
# For firebase
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
import sys # ARGV
import hashlib # SHA256
import time # Timestamp
# Global variables
msg=sys.argv1
now=time.time()
bank_key='string'
# Create Database handle
cred = credentials.Certificate('secret_key.json')
app = firebase_admin.initialize_app(cred)
db = firestore.client()
def write_data(i,c):
card_key="str"+str(i)
card_sha256=hashlib.sha256(card_key.encode()).hexdigest()
uni_key= bank_key.strip()+card_key.strip()
uni_sha256=hashlib.sha256(uni_key.encode()).hexdigest()
# Write data
card_data={
'bank_key':bank_sha256,
'card_key':card_sha256,
'master_key': 'dummy',
'number':ord(c)-ord('a')+1,
'time_stamp':now,
}
db.collection("card").document(uni_sha256).set(card_data)
# Write bank data
bank_sha256=hashlib.sha256(bank_key.encode()).hexdigest()
bank_data={
'bank_name':bank_key,
'time_stamp':now,
}
db.collection("bank").document(bank_sha256).set(bank_data)
# Write card data
i=1
for c in list(msg):
write_data(i,c)
i=i+1
write_data(i,chr(ord('a')-1)) # NULL terminate
https://gyazo.com/5d1ec7420b26010be90e1a8f2879f03c
Scratch -> Python
https://gyazo.com/46431ba9e8952164462a2ea1a19baea2
code:receive_str.py
# For firebase
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
import hashlib # SHA256
# Global variables
bank_key='string'
# Create Database handle
cred = credentials.Certificate('secret_key.json')
app = firebase_admin.initialize_app(cred)
db = firestore.client()
# Read card data
i=1
num=-1
result=""
while (num!=0):
card_key="str"+str(i)
card_sha256=hashlib.sha256(card_key.encode()).hexdigest()
uni_key= bank_key.strip()+card_key.strip()
uni_sha256=hashlib.sha256(uni_key.encode()).hexdigest()
ref_card = db.collection(u'card').document(uni_sha256)
dict=ref_card.get().to_dict()
num=int(dict'number')
if(num!=0):
result=result+chr(num+ord('a')-1)
i=i+1
print(result)
おわりに
やったこと
Stretch3でNumberBankを使った
利用例もいくつか紹介
外部のPythonスクリプトとのデータのやり取り
Scratchどうしの数字データのやり取りだけではなく、外部システムとのやり取りができるのは面白いと思います
Enjoy your Scratch life with NumberBank!!
#Scratch #Stretch3
#NumberBank
#Python