みなさんは毎年、酉の市に行って熊手を買っていますか?
私は酉の市に行ってずらりと並んだ屋台を眺めるのが好きで、毎年新宿の花園神社に行っています。今年も二の酉に花園神社に行き、コロナでの販売や入場の制限はあるものの、華やかな熊手が並んでいるのを見ると日常を取り戻しつつあるのを感じました。
酉の市には毎年行っているのですが、実は今まで熊手を買ったことがありませんでした…
いつも、ちょっとお高いので手が出せないと思っていたのですが、今年はサイバーおかんのサイバー熊手(ミニバージョン)の部材をいただくことができたので、自分で作って見ました!
熊手をIoT化!
サイバー熊手はちょっと変わった飾りやLEDがあってとても楽しいのですが、せっかくLEDを使うのであればIoT化できないかと考えました。熊手は家に常設されているので、センサーをつけて情報を取得したり、外部から取得した情報を表示するディスプレイとして使ったりすることができるのではないでしょうか。
熊手は毎年の酉の市で買い替えるのが通例なので、今回はインターネットから酉の市のカレンダー情報を表示して、買い替えを忘れないように通知するようにしてみます。
#システム構成
今回、以下の構成で熊手をIoT化します。
処理概要は以下の通りです。
- M5Atom から1時間ごとにenebularに酉の市かどうかをHTTPで問い合わせ
- enebularから暦APIにHTTPで今日の暦データを問い合わせ
- 暦APIが今日の暦データを応答
- enebularで今日が酉の市か判定(11月かつ十二支が酉)
- 今日が酉の市の場合はLEDバッジに「酉の市」と表示
LEDバッジをM5Atomで制御
熊手の通知用ディスプレイとしてはM5 Atom用 LEDバッジを使います。
LEDバッジをM5Flowと連携するためのサンプルコードが公開されているので、参考にして「酉の市」と通知するノードを作りました。
{"category":"LEDBadge","color":"#ff0000","blocks":["__LEDBadge_init","__LEDBadge_clear","__LEDBadge_close","__LEDBadge_TORI","__LEDBadge_GOOD","__LEDBadge_ONAIR"],"jscode":"// Block __LEDBadge_init\nvar __LEDBadge_init_json = {\n \"previousStatement\": null,\n \"nextStatement\": null,\n \"message0\": \"%1\",\n \"args0\": [\n {\n \"type\": \"field_label\",\n \"text\": \"init\"\n }\n ],\n \"colour\": \"#ff0000\"\n};\n\nwindow['Blockly'].Blocks['__LEDBadge_init'] = {\n init: function() {\n this.jsonInit(__LEDBadge_init_json);\n }\n};\n\nwindow['Blockly'].Python['__LEDBadge_init'] = function(block) {\n return `from machine import I2C\n_HT16K33_BLINK_CMD = const(0x80)\n_HT16K33_BLINK_DISPLAYON = const(0x01)\n_HT16K33_CMD_BRIGHTNESS = const(0xE0)\n_HT16K33_OSCILATOR_ON = const(0x21)\nclass HT16K33:\n def __init__(self, i2c, address):\n self.i2c = i2c\n self.address = address\n self._temp = bytearray(1)\n self.buffer = bytearray(16)\n self._write_cmd(_HT16K33_OSCILATOR_ON)\n self.blink_rate(0)\n self.brightness(1)\n def _write_cmd(self, byte):\n self._temp[0] = byte\n self.i2c.writeto(self.address, self._temp)\n def blink_rate(self, rate=None): # 1-3:fast-slow\n if rate is None:\n return self._blink_rate\n rate = rate & 0x03\n self._blink_rate = rate\n self._write_cmd(_HT16K33_BLINK_CMD |\n _HT16K33_BLINK_DISPLAYON | rate << 1)\n def brightness(self, brightness):\n if brightness is None:\n return self._brightness\n brightness = brightness & 0x0F\n self._brightness = brightness\n self._write_cmd(_HT16K33_CMD_BRIGHTNESS | brightness)\n def show(self):\n self.i2c.writeto_mem(self.address, 0x00, self.buffer)\n def fill(self, color):\n fill = 0xff if color else 0x00\n for i in range(16):\n self.buffer[i] = fill\n def _pixel(self, x, y, color=None):\n addr = 2 * y + x // 8\n mask = 1 << x % 8\n if color is None:\n return bool(self.buffer[addr] & mask)\n if color:\n self.buffer[addr] |= mask\n else:\n self.buffer[addr] &= ~mask\n return None` + \"\\n\";\n};\n\n// Block __LEDBadge_clear\nvar __LEDBadge_clear_json = {\n \"previousStatement\": null,\n \"nextStatement\": null,\n \"message0\": \"%1\",\n \"args0\": [\n {\n \"type\": \"field_label\",\n \"text\": \"clear\"\n }\n ],\n \"colour\": \"#ff0000\"\n};\n\nwindow['Blockly'].Blocks['__LEDBadge_clear'] = {\n init: function() {\n this.jsonInit(__LEDBadge_clear_json);\n }\n};\n\nwindow['Blockly'].Python['__LEDBadge_clear'] = function(block) {\n return `i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\nmatrix.fill(0)\nmatrix1.fill(0)\nmatrix.show()\nmatrix1.show()` + \"\\n\";\n};\n\n// Block __LEDBadge_close\nvar __LEDBadge_close_json = {\n \"previousStatement\": null,\n \"nextStatement\": null,\n \"message0\": \"%1\",\n \"args0\": [\n {\n \"type\": \"field_label\",\n \"text\": \"close\"\n }\n ],\n \"colour\": \"#ff0000\"\n};\n\nwindow['Blockly'].Blocks['__LEDBadge_close'] = {\n init: function() {\n this.jsonInit(__LEDBadge_close_json);\n }\n};\n\nwindow['Blockly'].Python['__LEDBadge_close'] = function(block) {\n return `i2c.deinit()` + \"\\n\";\n};\n\n// Block __LEDBadge_TORI\nvar __LEDBadge_TORI_json = {\n \"previousStatement\": null,\n \"nextStatement\": null,\n \"message0\": \"%1\",\n \"args0\": [\n {\n \"type\": \"field_label\",\n \"text\": \"TORI\"\n }\n ],\n \"colour\": \"#ff0000\"\n};\n\nwindow['Blockly'].Blocks['__LEDBadge_TORI'] = {\n init: function() {\n this.jsonInit(__LEDBadge_TORI_json);\n }\n};\n\nwindow['Blockly'].Python['__LEDBadge_TORI'] = function(block) {\n return `i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\ndata1 = [\n [0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0],\n [0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,1,0],\n [0,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0],\n [0,1,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0],\n [0,1,0,1,0,1,1,1,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0],\n [0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0],\n [0,1,0,0,0,0,0,1,0,0,1,0,1,1,0,0,0,0,1,0,0,1,0,0,1,0,1,1,0,0,0,0],\n [0,1,1,1,1,1,1,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0],\n]\nfor y in range(8):\n for x in range(16):\n matrix._pixel(x,y,int(data1[y][x]))\n matrix1._pixel(x,y,int(data1[y][x+16]))\nmatrix.show()\nmatrix1.show()` + \"\\n\";\n};\n\n// Block __LEDBadge_GOOD\nvar __LEDBadge_GOOD_json = {\n \"previousStatement\": null,\n \"nextStatement\": null,\n \"message0\": \"%1\",\n \"args0\": [\n {\n \"type\": \"field_label\",\n \"text\": \"GOOD\"\n }\n ],\n \"colour\": \"#ff0000\"\n};\n\nwindow['Blockly'].Blocks['__LEDBadge_GOOD'] = {\n init: function() {\n this.jsonInit(__LEDBadge_GOOD_json);\n }\n};\n\nwindow['Blockly'].Python['__LEDBadge_GOOD'] = function(block) {\n return `i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\ndata = [\n [0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0],\n [1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0],\n]\nfor y in range(8):\n for x in range(16):\n matrix._pixel(x,y,int(data[y][x]))\n matrix1._pixel(x,y,int(data[y][x+16]))\nmatrix.show()\nmatrix1.show()` + \"\\n\";\n};\n\n// Block __LEDBadge_ONAIR\nvar __LEDBadge_ONAIR_json = {\n \"previousStatement\": null,\n \"nextStatement\": null,\n \"message0\": \"%1\",\n \"args0\": [\n {\n \"type\": \"field_label\",\n \"text\": \"ONAIR\"\n }\n ],\n \"colour\": \"#ff0000\"\n};\n\nwindow['Blockly'].Blocks['__LEDBadge_ONAIR'] = {\n init: function() {\n this.jsonInit(__LEDBadge_ONAIR_json);\n }\n};\n\nwindow['Blockly'].Python['__LEDBadge_ONAIR'] = function(block) {\n return `i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\ndata2 = [\n [0,1,1,1,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,0],\n [1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],\n [1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,0,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [0,1,1,1,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n]\nfor y in range(8):\n for x in range(16):\n matrix._pixel(x,y,int(data2[y][x]))\n matrix1._pixel(x,y,int(data2[y][x+16]))\nmatrix.show()\nmatrix1.show()` + \"\\n\";\n};\n\n","code":{"init":["window['Blockly'].Python['__LEDBadge_init'] = function(block) {\n return `from machine import I2C\n_HT16K33_BLINK_CMD = const(0x80)\n_HT16K33_BLINK_DISPLAYON = const(0x01)\n_HT16K33_CMD_BRIGHTNESS = const(0xE0)\n_HT16K33_OSCILATOR_ON = const(0x21)\nclass HT16K33:\n def __init__(self, i2c, address):\n self.i2c = i2c\n self.address = address\n self._temp = bytearray(1)\n self.buffer = bytearray(16)\n self._write_cmd(_HT16K33_OSCILATOR_ON)\n self.blink_rate(0)\n self.brightness(1)\n def _write_cmd(self, byte):\n self._temp[0] = byte\n self.i2c.writeto(self.address, self._temp)\n def blink_rate(self, rate=None): # 1-3:fast-slow\n if rate is None:\n return self._blink_rate\n rate = rate & 0x03\n self._blink_rate = rate\n self._write_cmd(_HT16K33_BLINK_CMD |\n _HT16K33_BLINK_DISPLAYON | rate << 1)\n def brightness(self, brightness):\n if brightness is None:\n return self._brightness\n brightness = brightness & 0x0F\n self._brightness = brightness\n self._write_cmd(_HT16K33_CMD_BRIGHTNESS | brightness)\n def show(self):\n self.i2c.writeto_mem(self.address, 0x00, self.buffer)\n def fill(self, color):\n fill = 0xff if color else 0x00\n for i in range(16):\n self.buffer[i] = fill\n def _pixel(self, x, y, color=None):\n addr = 2 * y + x // 8\n mask = 1 << x % 8\n if color is None:\n return bool(self.buffer[addr] & mask)\n if color:\n self.buffer[addr] |= mask\n else:\n self.buffer[addr] &= ~mask\n return None` + \"\\n\";\n};\n\n","from machine import I2C\n_HT16K33_BLINK_CMD = const(0x80)\n_HT16K33_BLINK_DISPLAYON = const(0x01)\n_HT16K33_CMD_BRIGHTNESS = const(0xE0)\n_HT16K33_OSCILATOR_ON = const(0x21)\nclass HT16K33:\n def __init__(self, i2c, address):\n self.i2c = i2c\n self.address = address\n self._temp = bytearray(1)\n self.buffer = bytearray(16)\n self._write_cmd(_HT16K33_OSCILATOR_ON)\n self.blink_rate(0)\n self.brightness(1)\n def _write_cmd(self, byte):\n self._temp[0] = byte\n self.i2c.writeto(self.address, self._temp)\n def blink_rate(self, rate=None): # 1-3:fast-slow\n if rate is None:\n return self._blink_rate\n rate = rate & 0x03\n self._blink_rate = rate\n self._write_cmd(_HT16K33_BLINK_CMD |\n _HT16K33_BLINK_DISPLAYON | rate << 1)\n def brightness(self, brightness):\n if brightness is None:\n return self._brightness\n brightness = brightness & 0x0F\n self._brightness = brightness\n self._write_cmd(_HT16K33_CMD_BRIGHTNESS | brightness)\n def show(self):\n self.i2c.writeto_mem(self.address, 0x00, self.buffer)\n def fill(self, color):\n fill = 0xff if color else 0x00\n for i in range(16):\n self.buffer[i] = fill\n def _pixel(self, x, y, color=None):\n addr = 2 * y + x // 8\n mask = 1 << x % 8\n if color is None:\n return bool(self.buffer[addr] & mask)\n if color:\n self.buffer[addr] |= mask\n else:\n self.buffer[addr] &= ~mask\n return None"],"clear":["window['Blockly'].Python['__LEDBadge_clear'] = function(block) {\n return `i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\nmatrix.fill(0)\nmatrix1.fill(0)\nmatrix.show()\nmatrix1.show()` + \"\\n\";\n};\n\n","i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\nmatrix.fill(0)\nmatrix1.fill(0)\nmatrix.show()\nmatrix1.show()"],"close":["window['Blockly'].Python['__LEDBadge_close'] = function(block) {\n return `i2c.deinit()` + \"\\n\";\n};\n\n","i2c.deinit()"],"TORI":["window['Blockly'].Python['__LEDBadge_TORI'] = function(block) {\n return `i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\ndata1 = [\n [1,1,0,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0],\n [1,1,1,0,0,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n [1,1,1,0,0,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n [1,1,1,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0],\n [1,1,0,1,1,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n [1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,1,1,1,1,0,0,0],\n [1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n [1,1,0,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n]\nfor y in range(8):\n for x in range(16):\n matrix._pixel(x,y,int(data1[y][x]))\n matrix1._pixel(x,y,int(data1[y][x+16]))\nmatrix.show()\nmatrix1.show()` + \"\\n\";\n};\n\n","i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\ndata1 = [\n [1,1,0,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0],\n [1,1,1,0,0,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n [1,1,1,0,0,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n [1,1,1,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0],\n [1,1,0,1,1,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n [1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,1,1,1,1,0,0,0],\n [1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n [1,1,0,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0],\n]\nfor y in range(8):\n for x in range(16):\n matrix._pixel(x,y,int(data1[y][x]))\n matrix1._pixel(x,y,int(data1[y][x+16]))\nmatrix.show()\nmatrix1.show()"],"GOOD":["window['Blockly'].Python['__LEDBadge_GOOD'] = function(block) {\n return `i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\ndata = [\n [0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0],\n [1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0],\n]\nfor y in range(8):\n for x in range(16):\n matrix._pixel(x,y,int(data[y][x]))\n matrix1._pixel(x,y,int(data[y][x+16]))\nmatrix.show()\nmatrix1.show()` + \"\\n\";\n};\n\n","i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\ndata = [\n [0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0],\n [1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,0],\n [0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0],\n]\nfor y in range(8):\n for x in range(16):\n matrix._pixel(x,y,int(data[y][x]))\n matrix1._pixel(x,y,int(data[y][x+16]))\nmatrix.show()\nmatrix1.show()"],"ONAIR":["window['Blockly'].Python['__LEDBadge_ONAIR'] = function(block) {\n return `i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\ndata2 = [\n [0,1,1,1,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,0],\n [1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,0],\n [1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,0,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [0,1,1,1,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n]\nfor y in range(8):\n for x in range(16):\n matrix._pixel(x,y,int(data2[y][x]))\n matrix1._pixel(x,y,int(data2[y][x+16]))\nmatrix.show()\nmatrix1.show()` + \"\\n\";\n};\n\n","i2c = I2C(sda=25, scl=21, freq=100000)\nmatrix = HT16K33(i2c, 0x70)\nmatrix1 = HT16K33(i2c, 0x71)\ndata2 = [\n [0,1,1,1,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,0],\n [1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,0],\n [1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,0,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1],\n [1,1,0,0,0,1,1,0,1,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n [0,1,1,1,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,0,1,1],\n]\nfor y in range(8):\n for x in range(16):\n matrix._pixel(x,y,int(data2[y][x]))\n matrix1._pixel(x,y,int(data2[y][x+16]))\nmatrix.show()\nmatrix1.show()"]}}
最終的なM5Flowは以下の通りです。
HTTP RequestのURLはenebularの環境に合わせて変更する必要があります。
##enebularで酉の市を判定
今日が酉の市なのかはenebularから暦APIから暦データを取得して判定します。酉の市は「11月」かつ「十二支が酉」の日で判定できます。
[{"id":"5dc632c9.8078dc","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"7dfb04b8.53235c","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"fd950c48.030af","type":"http request","z":"5dc632c9.8078dc","name":"暦APIから暦を取得","method":"GET","ret":"txt","paytoqs":false,"url":"https://koyomi.zingsystem.com/api/?{{{query}}}","tls":"","persist":false,"proxy":"","authType":"","x":350,"y":160,"wires":[["9c8fa7e8.0cb398"]]},{"id":"6484639a.88ac3c","type":"change","z":"5dc632c9.8078dc","name":"クエリを変数にセット","rules":[{"t":"set","p":"query","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":140,"y":160,"wires":[["fd950c48.030af"]]},{"id":"26e08b69.549584","type":"function","z":"5dc632c9.8078dc","name":"十二支を取得","func":"msg.payload = msg.payload.datelist.date.zyunisi;\nreturn msg;","outputs":1,"noerr":0,"x":120,"y":280,"wires":[["8c77acce.3b411"]]},{"id":"f7dba057.5cb07","type":"json","z":"5dc632c9.8078dc","name":"JSONに変換","property":"payload","action":"obj","pretty":false,"x":110,"y":220,"wires":[["26e08b69.549584"]]},{"id":"9c8fa7e8.0cb398","type":"change","z":"5dc632c9.8078dc","name":"日付を固定値に変換","rules":[{"t":"change","p":"payload","pt":"msg","from":"....-..-..","fromt":"re","to":"date","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":160,"wires":[["f7dba057.5cb07"]]},{"id":"74300789.f68348","type":"change","z":"5dc632c9.8078dc","name":"日付からクエリを生成","rules":[{"t":"set","p":"payload","pt":"msg","to":"$fromMillis($millis(),'mode=d&cnt=1&targetyyyy=[Y0001]&targetmm=[M01]&targetdd=[D01]')\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":100,"wires":[["6484639a.88ac3c"]]},{"id":"5419c486.0555ac","type":"inject","z":"5dc632c9.8078dc","name":"酉の市テスト","topic":"","payload":"mode=d&cnt=1&targetyyyy=2021&targetmm=11&targetdd=09","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":100,"wires":[["6484639a.88ac3c"]]},{"id":"77a9a6d6.913d28","type":"debug","z":"5dc632c9.8078dc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":610,"y":300,"wires":[]},{"id":"1e76afe4.0512b","type":"change","z":"5dc632c9.8078dc","name":"日付から月を生成","rules":[{"t":"set","p":"month","pt":"msg","to":"$fromMillis($millis(),'[M01]')\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":350,"y":320,"wires":[["4c8a1706.cc11a8"]]},{"id":"4c8a1706.cc11a8","type":"switch","z":"5dc632c9.8078dc","name":"11月判定","property":"month","propertyType":"msg","rules":[{"t":"eq","v":"11","vt":"num"},{"t":"neq","v":"11","vt":"num"}],"checkall":"false","repair":false,"outputs":2,"x":320,"y":380,"wires":[["120b89fd.ca3da6"],["34827fea.df18a"]]},{"id":"d59427fc.8b5fa8","type":"http in","z":"5dc632c9.8078dc","name":"","url":"/tori","method":"get","upload":false,"swaggerDoc":"","x":320,"y":100,"wires":[["74300789.f68348"]]},{"id":"e5baab38.8c9228","type":"http response","z":"5dc632c9.8078dc","name":"","statusCode":"","headers":{},"x":650,"y":460,"wires":[]},{"id":"34827fea.df18a","type":"change","z":"5dc632c9.8078dc","name":"NG","rules":[{"t":"set","p":"payload","pt":"msg","to":"NG","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":500,"wires":[["77a9a6d6.913d28","e5baab38.8c9228"]]},{"id":"120b89fd.ca3da6","type":"change","z":"5dc632c9.8078dc","name":"OK","rules":[{"t":"set","p":"payload","pt":"msg","to":"OK","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":440,"wires":[["77a9a6d6.913d28","e5baab38.8c9228"]]},{"id":"8c77acce.3b411","type":"switch","z":"5dc632c9.8078dc","name":"十二支判定","property":"month","propertyType":"msg","rules":[{"t":"eq","v":"酉","vt":"str"},{"t":"neq","v":"酉","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":110,"y":340,"wires":[["1e76afe4.0512b"],["34827fea.df18a"]]}]
#完成品はこんな感じ
通常時はLEDには何も表示されていませんが、、、
酉の市がある日(2021年11月9日など)になると、通知されて忘れずに買い替えに行くことができるようになりました。
#今後の応用
今回は熊手をIoT化することで酉の市の通知をする機能を付与しました。
IoT化することで熊手にさまざまな機能を付加する応用が考えられます。
- 熊手に温湿度センサーやCO2センサーをつけて室内環境データ収集
- 熊手のスマートスピーカー化
- 外部からLEDを操作して派手な演出を自由にコントロール
- GPSセンサーで熊手の位置情報を把握して全国熊手マップを作成
- 占い機能を搭載し、熊手による運気の上昇具合を定量化
これからも enebular を活用して、さらなる熊手IoT化を推進していきましょう!