なくなりそうになったら購入時期を教えてくれるスマートスケール【Obniz・RaspberryPi】

使っているときには、そろそろなくなりそうだなと思うのですが、一旦その場を離れてしまうと購入することをつい忘れてしまうことが多くないですか。

それを通知してくれるような仕組みがないかなと思ってobnizで制作してみました。ついつい買い忘れるものをスマートスケールの上を置き場にしておけば常に監視して、購入時期を教えてくれます。購入通知も仕事終わりなどの時間帯で通知するようにしておけば、買い物の忘れもすくなくなるでしょう。プラスして内容をアマゾンの商品購入URLを送るようにしておけば、ワンタッチで購入もできます。Amazonダッシュボタンに似てるな。

youtu.be

システム概要

  • 適応対象:5kg以下の重さがわかるもの。使用により重さが変化するもの(お米、洗濯洗剤、台所洗剤、トイレットペーパー、シャンプー等)
  • 操作方法:センサーに乗せておく。事前に新品時の重さと補充時の重さの設定が必要
  • 拡張性:LINE Notify送信先をグループに設定することで、より購入の忘れを防ぐことができる。重複購入防止策のために、補充されたこともLINE Notifyで送信することも考える(一人暮らしようには不要)

使用した部品

部品 説明 ・備考
obniz Board / obniz Board 1Y obniz
RaspberryPi 3B Node.jsを実行するホスト
HX711センサー 電子スケール ロードセル計量センサ
デジタル・マイクロサーボ SG90 重量をアナログ値で表示

重さを量るセンサーは以下のものを使用

f:id:ueponx:20210714162105p:plain

使用したネットワークサービス

サービス名 備考
LINE Notify 連携したWebサービスからの通知を公式アカウントである「LINE Notify」から受信できるサービス

LINE Notify

f:id:ueponx:20210714162257p:plain

Node.jsライブラリ

ライブラリ名 内容
line-notify-nodejs LINE Notifyライブラリ
node-cron Node.js内でcronのような定時実行を行うライブラリ

システム構成図

構成図

f:id:ueponx:20210714162155p:plain

ソースコード

LINE Notifyを使用した通知は9時と18時に行うように指定しています。node-cronを使用することで、設定もcron同様に行うことができています。このライブラリは非同期で動作するようになっていて、時間設定のタイミングで動作してくれます。

cron.schedule('0 0 9,18 * * *', async function () {
  console.log("計測処理開始!");

ソースコード内の---LINENotifyトークンを入力---に関してはこのエントリーでは触れませんが、サービス登録時に表示されるトークンを入力してください。 同様にOBNIZ_ID_HEREのところにはお持ちのobnizのデバイスIDを入力してください。

また通知のトリガーとなる重さはソースコード内のconst triggerWeight = 40; //gとしているように40グラムを下回ったときに通知が行われます。

ソースコード

var Obniz = require("obniz");
//lineNotifyのトークンを入力する
const lineNotify = require('line-notify-nodejs')('---LINENotifyトークンを入力---');
const cron = require('node-cron');

//ObnizのデバイスIDを入力する 
let obniz = new Obniz("OBNIZ_ID_HERE");

let value = 0;
let weight = 0;
let weightMessage = "";
let sensor;
let servo;

const WeightMAX = 400; //g
const triggerWeight = 40; //g

obniz.onconnect = async function () {
    //hx711 設定
    sensor = obniz.wired("hx711" , {gnd:0, dout:1, sck:2, vcc:3} );
    sensor.setOffset(-8231198); //デバイスごとに調整が必要
    sensor.setScale(480.0); //デバイスごとに調整が必要
    //SG90 サーボ設定
    servo = obniz.wired("ServoMotor", {gnd:4,vcc:5,signal:6});
    servo.angle(0);

    //hx711 計測
    value = await sensor.getValueWait(10);
    weight = numberValueRound(Math.abs(value), 0.01);
    weightMessage = "残りの重さは" + Math.abs(weight) + "gです。";
    console.log(weightMessage);
    
    //SG90 サーボ制御
    servo.on();
    angle = weight / WeightMAX * 180;
    servo.angle(angle); 
    await obniz.wait(1000);
    servo.off();
}

cron.schedule('0 0 9,18 * * *', async function () {
  console.log("計測処理開始!");

  //hx711 計測
  value = await sensor.getValueWait(10);
  weight = numberValueRound(Math.abs(value), 0.01);
  weightMessage = "残りの重さは" + Math.abs(weight) + "gです。";
  console.log(weightMessage);
  
  //SG90 サーボ制御
  servo.on();
  await obniz.wait(1000);
  angle = weight / WeightMAX * 180;
  servo.angle(angle); 
  await obniz.wait(1000);
  servo.off();
  //console.log(angle,weight);

  //送信メッセージの作成
  if(weight < triggerWeight){
    //LineNotify送信
    lineNotify.notify({
      message: "そろそろ無くなりそうですよ。購入しましょう!" + weightMessage
    })
  }
  console.log("計測処理完了!");
});

//指定桁の四捨五入
function numberValueRound(value, base) {
  return Math.round(value * base) / base;
}

実行の様子

コンソールでの実行の様子

f:id:ueponx:20210714162514p:plain

LINE Notifyでのメッセージ通知

f:id:ueponx:20210714162536p:plain

食器洗剤を計測

f:id:ueponx:20210714162608p:plain

おわりに

ロードセルのキャリブレーションが結構大変でしたが、一度経験すれば大した作業ではありません。調整するのであれば1円玉が何枚かある方が調整がしやすいと思います。この程度の歪で重さって計測できるんだなと思ってかなり感心しました。電子ばかりも基本的には似たような構造なんでしょうね。

今回はobnizを使用して作成していますが、RaspberryPiだけでもいけるかな?後日試してみようと思っています。

ちなみにネットを検索すると以下のようなものが出てきた…orz

学生さん向けのオンラインNode-REDハンズオンをやってきました

コロナの関係で、地方の勉強会コミュニティはかなりひっそりとした状況。 基本的にオンラインでやれば地域間の格差もないですし、移動のコストもかからないので、運営・参加者双方にとってWin-Winの状況だと思います。それはわかっているんんだけど…

自分の所属しているNode-RED UG Tokaiもコロナ前に立ち上げたもののほとんど活動できていない状況で、閑古鳥泣いてる…。

そんな中、名城大学さんで行われている「ITエンジニア育成プロジェクト」さんからお声がけをいただきまして、名城大学の学生さん向けにNode-REDのハンズオンをさせていただく機会を頂きました。 内容は準備期間も限られていたこともあり、昨年UGで行ったオンラインハンズオンの内容の説明を初学者向けに修正して行う形式としました。

f:id:ueponx:20210714122619j:plain

こちらのQiitaエントリーを見ながらのハンズオンとなります

qiita.com

内容的には以下の書籍の1章から3章の内容を説明した形でしょうか。

久々のオンライン・ハンズオン

対面形式のハンズオンなどではやはり作業をしている方々の顔や雰囲気を読み取ることができるので、話す側としては、ここが詰まっているのかなと、簡単そうだからここは説明を簡単にしようなど、対応ができるのですがオンラインで名前だけがみえるという状況はかなり対応が難しいなと思いました。自分以外のオンラインサポートをしてくれたメンバーの方もチャットで大変なのかなと思っていました。

そういえばZoomってなんで画面共有者からチャットウインドウが見にくいのだろうか…

最初は進捗をまったりしようかなと思っていたのですが、反応が薄いし、状況もわからないので途中からは自分のペースですすめてしまった感じです。最後のほうは結構早口になってしまったかなと思いましたが、小一時間で内容を完走しました。

反省点・感想

今回は受講者が学生さんといっても学年にかなり開きがあり、周辺の理解度にも差があったので、Web知ってるるだろう…、REST APIという考え方もなんとかなるだろう…、JSON形式のデータが収受するところは図示しよう、などと事前想定をしていましたが、わりとその予想も雑だったかなと思いました。

今後は対象者がどのレベル感なのかはもう少し考えたほうがいいのかもしれません(常識かもしれないですが)。対面時のように様子がわかれば、説明時間の割り振りもできるのですが、オンラインでは事前情報が命ともいえますね。

ただ、比較的、資料を手取り足取りという感じで資料を作っていたのでハンズオンで挫折した方がいなかったのは良かったかなと思っています。

オンラインのハンズオンは、初学者から見ればスタートラインに立つハードルが結構高い印象をうけました。勉強を始めるための、スタートラインに立つ部分の需要は割とあるのかも?(それがICTリテラシーなのかも?)

私は、現在対面形式で小学生を相手にプログラミング教室をやっているのですが、オンラインとは全く違い、進捗の様子や楽しさの反応など非常にわかりやすくのですが、子供向けのオンライン授業はかなり関係値(人間関係)が出来上がったコミュニティ(学校など)または明確な目的(受験や学ぶ意欲)が存在しないと成立しにくいのかなと感じています。オンラインは否定しないけど、授業中の孤独感をどう埋めるかは大きな課題だと感じています。

本当に大学の先生方オンラインでよく心折れないなあと思いつつ、このエントリーは終わります。

今回、Node-REDのハンズオンを行う機会をいただいた、名城大学鈴木先生ありがとうございます。次はもっといい内容にしたいです!また、一緒にサポートをしていただいた石井さん、高尾さん、萩野さん、IBMの方々にもお礼申し上げます。

Windows11が発表されたので手持ちの古めのPCの対応状況をチェック

Windows11の発表が行われました。Windows10自体もかなり長い時間リリースされているので、このままでいくのかな?と思っていましたが、いよいよバージョンアップとなるようです。最近ではWSLなどの進展もありWindowsというOS自体も当初とかかなり変わってきたように思います。そろそろ家にあるPCたちも引導を渡されるのだろうかと思って、Windows11まで延命できるかなどを調べてみました。

公式サイトは以下のようなデザインになっています。壁紙はきれいな感じですね・・・背景を黒にしてしまう自分には全く関係ないですがw

www.microsoft.com

f:id:ueponx:20210705225116p:plain

f:id:ueponx:20210705225111p:plain

続きを読む

Raspberry PiでのRaspberry Pi PicoのMicroPython開発環境はどうなの?(2021.06)

先日のエントリではRaspberry Pi Pico(以下Pico)でLチカの次の段階ということでUSBデバイス(キーボード)を作ってみました。そのときの開発環境はWindowsPCにVisual Studio Codeをインストールして、USBストレージとして見えるPico(MicroPython環境設定済み)のファイルを編集するというようなものでした。それでも割と問題ないのですが、折角Picoを使っているので、開発環境すべてをRaspberry Pi印でそろえるっていうのはどうだろうかと考え、今回のこのようなものを書いてみました。

Raspberry PiPicoがあれば格安で開発できるんじゃね?という安易な考え方ではありますが、子どもたち向けにやるにはかなり価格的なハードルが下がるのかなという観点でもあります。

では、現時点(2021年6月)での開発環境を見てみようと思います。

過去エントリー参考

uepon.hatenadiary.com

続きを読む

Raspberry Pi Picoをカスタムキーボード化して「くぁwせdrftgyふじこlp」キーボード爆誕!

f:id:ueponx:20210610002739p:plain

(2021.06.11)コードの記述が短縮できたので追記しました

少し前からRaspberry Pi Pico(以下Pico)のネタを書いていますが、そろそろやろうとしていた、キーボード化に挑戦してみます。 んで、とりあえずはマクロキー化をする感じで考えていましたが、少しネタっぽい感じで「くぁwせdrftgyふじこlp」というフレーズを1キーで入力できる、バカキーボードを作ってみることにします。基本的なプログラミングに関しては、ほぼ同じなので、これを見ながら自分のお好みのものを作ってもらえればと思います。

早速、その過程を記載していこうと思います。

まずはLチカ

以前のエントリーではREPL環境でのインタプリタでLチカを行っていましたが、今回はファイルにMicroPythonのコードを書いて実行していこうと思います。PicoをUSB接続するとストレージとして認識されるのでその中にあるcode.pyを編集していくことになります。

※RaspberryPiで開発環境を整えるためにThonny Python IDEMU Editorを使おうかなと思ったのですが、普通にUSBストレージ内のファイルをVisual Studio Codeで編集して保存するだけで開発できたので、そのまま開発していこうと思います。RaspberryPiでの開発環境については別のエントリーで言及しようかと

USBストレージ内のcode.pyというファイルを編集するだけでファイルの中身が自動的に実行されます。ネット情報ではmain.pyというファイルでもいいのかなと思ったのですが、code.pyのほうが優先されるようです。

まずはLチカを行ってみます。本体のLEDのはGP25として定義されています。ではこのLEDを点灯させるコードを書いていこうと思います。

本体LEDを使用してLチカ

import digitalio
from board import *
import time

led = digitalio.DigitalInOut(GP25)
led.direction = digitalio.Direction.OUTPUT

while True:
    led.value = True
    time.sleep(0.1)
    led.value = False
    time.sleep(0.1)

上記のコードで本体のLチカを行うことができます。基本的にはIOピンを出力設定をして、on/offを設定するだけで点滅ができます。

本体上のLED位置

f:id:ueponx:20210610000652p:plain

Lチカの様子 youtu.be

そこまで難しくはありません。

タクトスイッチを入れる

バカデバイスとはいっても自作キーボードなのでやっぱりボタンが必要です。そこでタクトスイッチをIOに接続して、それを押したらLEDを点灯させてみます。

GP13ピンにタクトスイッチを接続して、プルダウンモードで動作をさせます。(押したときにON=Trueになる)

f:id:ueponx:20210609235610p:plain

今回は少し大きめのタクトスイッチがあったので、それを使ってみました。もちろん一般的なタクトスイッチでも動作には問題ありません。

f:id:ueponx:20210610004155j:plain

タクトスイッチを押すと本体のLEDをLチカさせる

import board
import digitalio

led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT
button = digitalio.DigitalInOut(board.GP13)
button.switch_to_input(pull=digitalio.Pull.DOWN)

while True:
    led.value = button.value

動作の様子

youtu.be

あともう少しでキーボードが完成になります。

PicoをUSBキーボード化する

PicoをUSBキーボード化するにはライブラリが必要になります。USBストレージのlibディレクトリにAdafruit HID Libraryをコピーすることでライブラリのインストールができます。

ライブラリのダウンロード

ライブラリに関しては以下のリンクからダウンロードできます。CircuitPythonのバージョンによってファイルが異なるので、導入したバージョンをみてファイルをダウンロードして展開を行ってください。

circuitpython.org

自分は以下のuf2ファイルを使用してMicroPython環境を作成したのでBundle Version 6.x側をダウンロードしました。

f:id:ueponx:20210610220032p:plain

f:id:ueponx:20210610215924p:plain

ダウンロードが終わったら、展開をしておきましょう。ライブラリもかなり大量のファイルがあるのでかなりサイズが大きいです。

f:id:ueponx:20210610223253p:plain

Picoへライブラリーをコピー

USBのデバイス化をおこなうライブラリは先程のファイルを展開した中のadafruit_hidフォルダがあるので、USBストレージのlibフォルダにコピーします。他所の情報ではコピーするとは書いてあったのですが、ファイル単体なのかフォルダごとなのかがわからない記述も多かったのですが、試したところ「フォルダごとコピーすればOK」だったようです。

コピー後のツリー表示は以下のようになっていれば動作します。

f:id:ueponx:20210610001323p:plain

f:id:ueponx:20210610001131p:plain

USBのHIDドライバもかなり種類がありますね。

f:id:ueponx:20210610001134p:plain

「くぁwせdrftgyふじこlp」キーボードを作る!

ライブラリファイルのコピーが終わったらあとはcode.pyを以下の様に編集していきます。

先程のタクトキーを押したらLEDが点灯するというのにキー操作を行う処理を追加すればほぼ終わりです。

タクトスイッチを押すと、キーボードで「くぁwせdrftgyふじこlp」を入力する(入力中は本体のLEDを点灯させる)

import time
import board
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode

def keyInput(keycodeName):
    keyboard.send(keycodeName)

keyboard = Keyboard(usb_hid.devices)

led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT
button = digitalio.DigitalInOut(board.GP13)
button.switch_to_input(pull=digitalio.Pull.DOWN)
led.value = False

while True:
    if button.value:
        led.value = True
        # 日本語変換モードに切り替える
        # keyboard.send(Keycode.ALT, Keycode.GRAVE_ACCENT)

        keyInput(Keycode.Q)
        keyInput(Keycode.A)
        keyInput(Keycode.W)
        keyInput(Keycode.S)
        keyInput(Keycode.E)
        keyInput(Keycode.D)
        keyInput(Keycode.R)
        keyInput(Keycode.F)
        keyInput(Keycode.T)
        keyInput(Keycode.G)
        keyInput(Keycode.Y)
        keyInput(Keycode.H)
        keyInput(Keycode.U)
        keyInput(Keycode.J)
        keyInput(Keycode.I)
        keyInput(Keycode.K)
        keyInput(Keycode.O)
        keyInput(Keycode.L)
        keyInput(Keycode.P)
        keyInput(Keycode.ENTER)

        # 日本語変換モードから英数モードに切り替える
        # keyboard.send(Keycode.ALT, Keycode.GRAVE_ACCENT)
        led.value = False

adafruit_hid.keyboard()の引数にキーの名前をしてすればキーモード入力ができます。以下が参考になります。

circuitpython.readthedocs.io

キーコードは以下が参考になると思います。

github.com

ちなみに今回は入力時には日本語入力モード変換にしてあるという前提で処理を記述しています。もし英数入力モードから日本語入力モードに変換する部分も入れたい場合にはコメントアウトしている部分を処理に入れてください。日本語109キーボードにある【全角/半角】キーは使えないので、USキーボード同様に【ALT】キー+ 【`】キーで日本語入力モードに変えています。この処理がトグルなので、元の状態関係なく日本語入力にして元に戻すにはWindowsの場合はIMEなどの設定を変更する必要があります。(ちょっと面倒)

あと【`】はバッククォートだと思っていたのですが、キーコードとしてはGRAVE_ACCENTを使うようです。

ja.wikipedia.org

では動作させてみます。

youtu.be

追記(2021.06.11)

先程のコードではいちいち1つのキーを押下するのにコードを書いていましたが、さすがにこれではコードが大量になってしまいます。そこで、USB_HIDにあるキーボードレイアウトというモジュールadafruit_hid.keyboard_layout_usを使用することで、キーコードの指定ではなく文字列を引数にすることで簡単に入力ができます。特殊キーの同時入力はできませんが、シフトキーなど押しながらの入力に関しては文字を判別してキーコードを判別してくれるのでかなり記述は楽になります。

adafruit_hid.keyboard_layout_usモジュールを使用して書き直す

import time
import board
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS #追加部分

def keyInput(keycodeName):
    keyboard.send(keycodeName)

keyboard = Keyboard(usb_hid.devices)
layout = KeyboardLayoutUS(keyboard)  #追加部分

led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT
button = digitalio.DigitalInOut(board.GP13)
button.switch_to_input(pull=digitalio.Pull.DOWN)
led.value = False

# 「くぁwせdrftgyふじこlp」キーボード

while True:
    if button.value:
        led.value = True
        # 日本語変換モードに切り替える
        # keyboard.send(Keycode.ALT, Keycode.GRAVE_ACCENT)

        layout.write('qawsedrftgyhujikolp\n') #変更部分

        # 日本語変換モードから英数モードに切り替える
        # keyboard.send(Keycode.ALT, Keycode.GRAVE_ACCENT)
        led.value = False

これでかなりコードが短くなりました。あくまでもキーコードに関してはUS配列のキーボードのものを踏襲するので日本語109などとキーの刻印が違うときには少し挙動が変わるので注意が必要かもしれません。

おわりに

PicoをキーボードエミュレーションさせることでUSBキーボードにすることができました。タクトスイッチにキーバインドを割り当てることで目的のマクロキーボードを作る事ができます。キーボード以外にもHIDデバイスである、ゲームパッドバイスにすることやマウスとしても使用することができるので、ちょっとしたデバイスならすぐできてしまうのかも。

ゲームなどのキーボードを複数使うような操作もこれならできちゃいそうです。チート行為になる可能性があるのでその辺りは注意してください。

せっかく作った「くぁwせdrftgyふじこlp」キーボードですがそう使う機会はなさそうですけどねw

参考

uepon.hatenadiary.com