ã€ãŸãããã®ãããžã§ã¯ãã«ã¯2ã€ã®æ©èœããããŸãã 1ã€ç®ïŒããŒãã«ã¯é³å£°ã³ãã³ãã䜿çšããŠGoogle Smart HomeããHerokuã«æ¥ç¶ããã2ã€ç®ïŒHââerokuãšããŒãã«èªäœã¯MQTT Internet ofThingsãããã³ã«ã䜿çšããŠéä¿¡ããŸãã MQTTã¯ãInternet of Thingsã«ãšã£ãŠããŸãç§ãã¡ãçŽé¢ããªããã°ãªããªãä»ã®ããã€ãã®é害ãå æããããã®åªãããœãªã¥ãŒã·ã§ã³ã§ãã
ãŸã第äžã«ãç§ã¯ãã æ¥œãã¿ã®ããã«ãã®ãããžã§ã¯ãããããšèšããŸãããã®èšäºãããããããŠãæéããããŠèªåã®ããšãããæ°ã«ãããŠãããããšãé¡ã£ãŠããŸãã
ããŒããŠã§ã¢éšå
ä»äºã®æåã®ããããŠããããæãé£ããéšåã¯ãããŒãã«ã®åèšèšã§ããéå»ã®äººçã§ã¯ãããŒãã«ã«ã¯åãå€ãå¯èœãªãã³ãã«ããããããŒãã«ãããã®ç«¯ã«ãããŸãããæåã¯ãããŒãã«ã®ãã¶ã€ã³ãéªéããããšãªãããã³ãã«ã®ç©Žã«äœããåãä»ããããšãèããŸãããã¢ãŒã¿ãŒãããŒãã«ã«åãä»ããæ¹æ³ãçè§£ããããã«ããã€ãã®ãã©ã€ããè³Œå ¥ããŸãããã圹ã«ç«ã¡ãŸããã§ãããããããã¢ã€ãã¢ãæµ®ãã³ãŸãããããŒãã«å šäœã®é·ãã«æ²¿ã£ãŠèµ°ããããã§ãèãæ¥ç¶ããŠåæã«äžäžããããã«ããŸãããããã«åããã©ã€ããåãä»ãããšããã«ãã䜿ã£ãŠããããã¢ãŒã¿ãŒã«æ¥ç¶ã§ããŸããèšèšã«ããŸãå¹²æžããããšãªããããŒãã«ã«ã¢ãŒã¿ãŒãè£ åããããšãå¯èœã§ãã
ãã«ã¯ã®éèŠæ§
é©åãªãã©ã€ããšãã«ããæ³šæããåŸãç§ã¯ã¢ããŸã³ã§é«ãã«ã¯ã¢ãŒã¿ãŒãæ¢ãå§ããŸããããããŠ-ãããå¥è·¡ïŒ -ç§ã¯å€ãã®é©åãªãšã³ãžã³ãèŠã€ããŸããïŒãšãããâŠå°ããªã¢ãŒã¿ãŒãè²·ã£ãŠãäžåœããã®å°çãçŽ1ã¶æåŸ ã¡ãŸãããã¢ãŒã¿ãŒãã€ãã«å°çãããšããç§ã¯ãšãŠãè奮ããŸããïŒé±æ«ããããããã¹ãŠããŸãšããŠãé»åãã¹ã¯ãæã«å ¥ããã®ãåŸ ã¡ãããŸããã§ããã
ç©äºã¯èšç»éãã«é²ãŸãªãã£ããç§ã¯ããŒãã«ã®éå±ããã«ã«ãããçšã®ç©Žãéããã®ã«äžæ¥ãè²»ãããŸãããåœæã¯ãã³ãããŒã«ããæã£ãŠããªãã£ãã®ã§ãæã£ãããæéãããããŸãããäžæ¥ã®çµããã«ãç§ã¯ããŒãã«ã®çµã¿ç«ãŠãçµãããããè©Šãæºåãã§ããŸããã
ã¢ãŒã¿ãŒããªã³ã«ãããã¹ã¯ããã黿ºã®é»å§ããªã³ã«ããŸããã...äœãèµ·ãããŸããã§ãããæ°ååŸãã¢ãŒã¿ãŒãå転ãå§ããååŸãããã«ãã®æ¯ãã¬ã¿ã¬ã¿é³ŽããŸããããããã2ã€ã®æèšãåŠã³ãŸããããã«ããæããã«æ©èœããŠããªãããšãšããé«ãã«ã¯ã®ã¢ãŒã¿ãŒããšããèšèã¯ãäœã§ãæã¡äžããããšãã§ããããšããæå³ã§ã¯ãããŸããã2çªç®ã®ã¬ãã¹ã³ã¯ãã¢ãŒã¿ãŒãæãšæ¯ã¹ãŠã©ãã ã倧ãããã確èªããããšã§ããç§ã®ã¯å°ããããšã倿ããŸããïŒ
åçã®å·ŠåŽã¯ã¢ãŒã¿ãŒãšãã«ãã§ããå³äžã¯ããŒãã«ã«åãä»ããããã¢ãŒã¿ãŒã§ãïŒããã«ã€ããŠã¯åŸã§è©³ãã説æããŸãïŒãå³äžã§ã¯ãã¢ãŒã¿ãŒã¯ããŒãã«ã®æå®ã®äœçœ®ã«ãããŸãã
é©åãªã¢ãŒã¿ãŒ
é©åãªã¢ãŒã¿ãŒãéžæããã«ã¯ãåäžãæã¡äžããã®ã«å¿ èŠãªãã«ã¯ãèšç®ããå¿ èŠããããŸããããããããã«ç°¡åããšããããšã«é©ããŸããã
ãã«ã¯ã¯ãåã«ã¬ããŒã¢ãŒã ã®é·ããæãããã®ã§ãã
ããŠãç§ã¯ã¬ããŒã¢ãŒã ïŒããã¯ããŒãã«ãã³ãã«ã§ãïŒãæã£ãŠããŸãããã¬ããŒã¢ãŒã ãç°¡åã«åãåãèšç®ããããšã ããå¿ èŠã§ããããã«ã¯ãžã£ã°ããã³ãã«ã«çµã³ä»ããŠããŒãã«ã«ããŒãããã¬ããŒãå転ãå§ãããŸã§ãžã£ã°ã«åŸã ã«æ°Žã远å ããŸãããæ°Žå·®ãããã£ã±ãã«ãªã£ãç¶æ ã§ãã³ãã«ãäžã«åãããšã§ããããããã³ãã«ãåããããããã«ããŸãããã¬ããŒã¢ãŒã ã®é·ãã¯11cmã§ãå¿ èŠãªåã¯4ãã³ãã§ããããšãããããŸããããããã®æ°å€ãåŒã«ä»£å ¥ãããšãã¢ãŒã¿ãŒã¯å°ãªããšã19.95 kg / cmã®ãã«ã¯ãçæããå¿ èŠãããããšãããããŸããããããŠç§ã¯åœŒãæ¢ãå§ããŸããã
ç§ã¯ããŒãã«ãäžå¯éçã«äœãçŽãããšã«ããŸãããããŒãã«ã®çãäžãéãããããäžç©ºã§ããããšãç§ã¯ç¥ã£ãŠããŸããããã€ã³ã·ã£ããã¢ãŒã¿ãŒãæ¢ããåŸãããããã«ããããŠãã¢ãŒã¿ãŒãçãäžã«çœ®ããŠçµã¿ç«ãŠçŽãããšãã§ããŸããã 20 kg / cmã®ãã«ã¯ã§2ã€ã®ã¢ãŒã¿ãŒãè³Œå ¥ããããšã§ãããŒãã«ãæã¡äžããã®ã«ååãªãã«ã¯ãããããšã確èªããŸããã
å¥ã®çŸããåææ¥ã«ãç§ã¯ããŒãã«ã4ã€ã«åè§£ããããããçµã¿ç«ãŠããšãã«äœ¿çšã§ããããã«ã¢ãŒã¿ãŒã·ã£ãããåæããŸãããã¢ãŒã¿ãŒã«åãããã«éå±ã«ããã«ç©ŽãéããŸãããä»åã¯ãã«ãããããŸããã§ãããã¢ãŒã¿ãŒã¯ãããã«çŽæ¥æ¥ç¶ãããŠããŠã穎ã¯ããªã倧ããã£ãã§ãã倿¹ã«ãªããšãæºãçµã¿ç«ãŠçŽããŠäºåçšåãç©ã¿èŸŒã¿ãŸããã
äžã®2ã€ã®åçã¯ãããŒãã«ã«å®å šã«åãä»ããããã¢ãŒã¿ãŒã§ããäžã®2ã€ã®åçã¯ãã¢ãŒã¿ãŒã®å©ããåããŠããŒãã«ã®é·ãã«æ²¿ã£ãŠèµ°ãäžäœåã®ãããã§ãã
ã¢ãŒã¿ãŒãæ¥ç¶ããŠé»æºã«æ¥ç¶ããŸããã黿ºãå ¥ãããšãããŒãã«ãåãã®ãèŠããŸããïŒä»åã¯ã¢ãŒã¿ãŒã®ãµã€ãºãæ£ããèšå®ããã®ã§ãèªä¿¡ãã€ããŸããã確ãã«ãšã³ãžã³ã®ãã¯ãŒã2åã«ããŸãããããšã³ãžã³ãåãã®ãèŠãã®ã¯çŽ æŽãããã£ãã§ãïŒ
ãã ããããŒãã«ãé ãããšãæç¢ºã«ããŠãããŸããç§ã¯å人ã«ããŒãã«ã®ä»çµã¿ã瀺ãããã«ãããªãæ®åœ±ããŸããããããŒãã«ãããŒãã«ã®äžã®äœçœ®ãå€ããã®ã§5åéèŠãªãããã«ã圌ã¯ãããªã®æéå éããªã³ã«ããå¿ èŠããããŸããã
売äžé«ã¯éèŠã§ããæçµç
ã€ãã«ç§ã¯ããããã¹ãŠãã«ã¯ãšå転ã®2ã€ã«åž°çããããšã«æ°ã¥ããŸãããæ¢ç¥ã®ãã«ã¯ã§ååãªå転æ°ã®ã¢ãŒã¿ãŒãèŠã€ããå¿ èŠããããŸããã
ããã»ã©é£ããã¯ãããŸããã§ããããã€ã³ã·ã£ããã¢ãŒã¿ãŒã¯èŠã€ãããŸããã§ããããã·ã³ã°ã«ã·ã£ããã¢ãŒã¿ãŒããã€ã³ã·ã£ããã¢ãŒã¿ãŒã«å€ããé·æ¹åœ¢ã®ã®ã¢ããã¯ã¹ãèŠã€ããŸãã ã
èŠããã«ãç¿æã¯äžåœããã®ã®ã¢ããã¯ã¹ãåŸ ã€æã§ãããåŸ ã£ãåŸã®æ¬¡ã®åææ¥ã¯ãé©åãªé床ã§ããŒãã«ãåãããŠããŸããã
æåŸã®ã¢ãŒã¿ãŒèªäœãå·ŠåŽã«ãããåãä»ããããŠããã¢ãŒã¿ãŒãå³åŽã«ãããŸããå°ããªããŒããŠã§ã¢ãšããããã®ãœãããŠã§ã¢ã
åäžã®é«ããå¶åŸ¡ããããã ãã«æšªããã£ãŠãããæºã®äžã®å·šå€§ãªé»æºã«æºè¶³ããŠããŸããã§ããããŸããããŒãã«ã®äœçœ®ãååŸã«å€ããããã«ãã¯ã€ã€ãŒã亀æããŸãããå°ããªåé¡ã§ããããããžã§ã¯ãã¯çæ³çã«ã¯ãã¿ã³ãæŒãã ãã§ãè€æ°ã®é«ãã®ããªã»ãããæã€ããã«è¡ãããŸããã
ãã«ãŒãã¥ãŒã¹
æåã®è§£æ±ºçã¯ãBluetoothãããŒãã«ã«è¿œå ããããšã§ãããçµå±ã®ãšãããå®¶ã®äžã®ã»ãŒãã¹ãŠã®ããã€ã¹ã«NluetoothãæèŒãããŠããããã«èŠããé»è©±ã¯ç§ã®æºã®ãããªãã®ã«ãšã£ãŠäŸ¿å©ãªå¶åŸ¡ã€ã³ã¿ãŒãã§ãŒã¹ã®ããã§ãã
ã ããä»ãç§ã¯ã¢ãŒã¿ãŒã³ã³ãããŒã©ãŒããŒãã忬§ã®NRF52ãã«ãŒãã¥ãŒã¹ããŒããè·é¢ã»ã³ãµãŒãæã«å ¥ããã³ã³ãããŒã©ãŒã®ãã¡ãŒã ãŠã§ã¢ããããå§ããŸããã
èšäºã®çµããã«ãç§ããããžã§ã¯ãã®ããã«æžãããœãããŠã§ã¢ãšãã¡ãŒã ãŠã§ã¢ãžã®ãªã³ã¯ãæ®ããŸããã³ãŒãã«ã€ããŠãæ°è»œã«ã³ã¡ã³ãããŠãã ãããç§ã¯ããã®ãã¡ãŒã ãŠã§ã¢éçºè ã§ã¯ãªãã®ã§ãã¬ã€ãã³ã¹ãåãåããããšæããŸãã
ç°¡åãªç޹ä»ãšããŠïŒESP32ã¯ãArduinoã©ã€ãã©ãªã䜿çšããŠC ++ã§èšè¿°ãããé»è©±ã®BLEã¿ãŒããã«ã¢ããªãšå¯Ÿè©±ããŸãã BLEã®ã€ã³ã¹ããŒã«ãšæ§æã¯éåžžã«è€éã§ãããŸããBLEãä»ããŠå¶åŸ¡ãããå€ã®ãã¹ãŠã®ç¹æ§ãäœæããå¿ èŠããããŸããç¹æ§ãã³ãŒãå ã®å€æ°ãšèããŠãã ããã BLEã¯ã倿°ãè€æ°ã®ãã³ãã©ãŒã§ã©ããããŠããã®å€æ°ã®å€ãååŸããã³èšå®ããŸãã
次ã«ãç¹æ§ã¯ç¬èªã®UUIDãæã€ãµãŒãã¹ã«ããã±ãŒãžåãããŸããããã«ããããµãŒãã¹ãäžæã«ãªããã¢ããªã±ãŒã·ã§ã³ããèå¥ã§ããããã«ãªããŸããæåŸã«ããã®ãµãŒãã¹ãåºåãã€ããŒãã«è¿œå ããŠãããã€ã¹ããµãŒãã¹ãæ€åºã§ããããã«ããå¿ èŠããããŸãããªã¢ãŒãããã€ã¹ããµãŒãã¹ã«æ¥ç¶ãã仿§ãä»ããŠããŒã¿ãéä¿¡ãããšãããŒãã«ã¯ããŠãŒã¶ãŒãé«ããå¥ã®ããªã»ããã«èª¿æŽããããšãæãã§ããããšãèªèããç§»åãéå§ããŸãã
é«ã調æŽã®ããã«ãã¯ãŒã¯ãããã«ã¯çŸåšã®é«ããæ€åºããTFMini-SLiDARã»ã³ãµãŒããããŸããããã¯æ¥œããã»ã³ãµãŒã§ããå®éã«ã¯ã¬ãŒã¶ãŒã§ããå ŽåãLiDARãšåŒã°ããŸããå åŠç³»ãšLEDã䜿çšããŠãèµ€å€ç·ã®é£è¡æéãæ±ºå®ããŸããäœããã®æ¹æ³ã§ãã»ã³ãµãŒã¯ããŒãã«ã®é«ããæ±ºå®ããŸããæ¬¡ã«ãå¶åŸ¡ç€ã¯çŸåšã®é«åºŠãšèŠæ±ãããé«åºŠã®å·®ãæ€åºããã¢ãŒã¿ãŒãå§åããŸããã¢ãŒã¿ãŒã¯ç®çã®æ¹åã«å転ããŸããã³ãŒãã®äž»èŠéšåã®äžéšã以äžã«ç€ºããŸããããã¡ã€ã«å šäœãããã§ç¢ºèªã§ã ãŸãã
void setup()
{
Serial.begin(115200);
Serial2.begin(TFMINIS_BAUDRATE);
EEPROM.begin(3); // used for saving the height presets between reboots
tfminis.begin(&Serial2);
tfminis.setFrameRate(0);
ledcSetup(UP_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);
ledcAttachPin(UP_PWM_PIN, UP_PWM_CHANNEL);
ledcSetup(DOWN_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);
ledcAttachPin(DOWN_PWM_PIN, DOWN_PWM_CHANNEL);
state_machine = new StateMachine();
state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL);
BLEDevice::init("ESP32_Desk");
...
BLEServer *p_server = BLEDevice::createServer();
BLEService *p_service = p_server->createService(BLEUUID(SERVICE_UUID), 20);
/* ------------------- SET HEIGHT TO PRESET CHARACTERISTIC -------------------------------------- */
BLECharacteristic *p_set_height_to_preset_characteristic = p_service->createCharacteristic(...);
p_set_height_to_preset_characteristic->setCallbacks(new SetHeightToPresetCallbacks());
/* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */
BLECharacteristic *p_move_desk_up_characteristic = p_service->createCharacteristic(...);
p_move_desk_up_characteristic->setCallbacks(new MoveDeskUpCallbacks());
/* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */
BLECharacteristic *p_move_desk_down_characteristic = p_service->createCharacteristic(...);
p_move_desk_down_characteristic->setCallbacks(new MoveDeskDownCallbacks());
/* ------------------- GET/SET HEIGHT 1 CHARACTERISTIC ------------------------------------------ */
BLECharacteristic *p_get_height_1_characteristic = p_service->createCharacteristic(...);
p_get_height_1_characteristic->setValue(state_machine->getHeightPreset1(), 1);
BLECharacteristic *p_save_current_height_as_height_1_characteristic = p_service->createCharacteristic(...);
p_save_current_height_as_height_1_characteristic->setCallbacks(new SaveCurrentHeightAsHeight1Callbacks());
/* ------------------- GET/SET HEIGHT 2 CHARACTERISTIC ------------------------------------------ */
...
/* ------------------- GET/SET HEIGHT 3 CHARACTERISTIC ------------------------------------------ */
...
/* ------------------- END CHARACTERISTIC DEFINITIONS ------------------------------------------ */
p_service->start();
BLEAdvertising *p_advertising = p_server->getAdvertising();
p_advertising->start();
xTaskCreate(
updateDeskHeight, // Function that should be called
"Update Desk Height", // Name of the task (for debugging)
1024, // Stack size
NULL, // Parameter to pass
5, // Task priority
NULL // Task handle
);
}
ãã¡ã€ã«ã«ã¯ããã«å€ãã®ããšãèµ·ãã£ãŠããŸããããã®ã³ãŒãã«ã¯äœãèµ·ãã£ãŠããã®ããçè§£ããã®ã«ååãªã³ã³ããã¹ãããããŸããæåã§ã®ç§»åãããªã»ããå€ã®èšå®ãšååŸããããŠæãéèŠãªããšãšããŠãããŒãã«ãããªã»ããã«åããããªã©ããã¹ãŠã®ç¹æ§ã«å¯ŸããŠãã¹ãŠã®BLEã³ãŒã«ããã¯ãäœæããã³æ§æããããšã«æ³šæããŠãã ããã
äžã®ç»åã¯ãããŒãã«ã®é«ãã調æŽããããã®ç¹æ§ãšã®çžäºäœçšã瀺ããŠããŸããããºã«ã®æåŸã®ããŒã¹ã¯ãçŸåšã®ããŒãã«ã®é«ãããŠãŒã¶ãŒã®åžæããé«ããèªèããããã2ã€ã®å€ãåŠçããã¹ããŒããã·ã³ã§ãã
ã ããã€ãã«ç§ã¯èªåãããããããšãäœã§ãããããŒãã«ãæã«å ¥ããŸãããé«ããããªã»ããã«ä¿åããã¡ã¢ãªããé«ããæœåºããŠãããŒãã«ããæ°ã«å ¥ãã®äœçœ®ã«èšå®ããããšãã§ããŸãããBLEã¿ãŒããã«ã䜿çšããŸãã é»è©±ãšã³ã³ãã¥ãŒã¿ãŒã§çã®ã¡ãã»ãŒãžããã¹ã¯ã«éä¿¡ãããã®äœçœ®ãç£èŠã§ããããã«ããŸãããããŸããããŸããããBLEãšã®æŠããå§ãŸã£ãã°ããã ãšæããŸããã
裞ã®Bluetoothã€ã³ã¿ãŒãã§ã€ã¹...çŸæç¹ã§æ®ã£ãŠããã®ã¯ãiOSçšã®ã¢ããªã±ãŒã·ã§ã³ã®äœææ¹æ³ãåŠã¶ããšã ãã§ãã...
ãã®åŸã劻ã¯ãããžã§ã¯ãå šäœãå€ããäœããèšããŸããã
ãã£ããããŠGoogleã¢ã·ã¹ã¿ã³ããªã¹ãã«æ°ããããã€ã¹ã远å ããããšã«å ããŠãããŒãã«ãå¶åŸ¡ããããã«iOSã¢ããªã±ãŒã·ã§ã³ãäœæããå¿ èŠã¯ãããŸããã§ããããããŠãããªãã¯ãã¯ãããªãã®é»è©±ãé«ãã調æŽããããã«æã䌞ã°ãå¿ èŠã¯ãããŸããã§ãããå¥ã®å°ããªåå©ïŒ
ã¢ãã®ã€ã³ã¿ãŒãããã远å ãã
ããã§ã¯ãGoogle Smart Homeãä»ããŠãã¹ã¯ãé³å£°å¶åŸ¡ã«ã¢ããã°ã¬ãŒãããæ¹æ³ãšãWi-Fi察å¿ã«ããæ¹æ³ã«ã€ããŠèª¬æããŸãããã
Wi-Fiã®è¿œå ã¯ç°¡åã§ããã NordicNRF52ãã€ã¯ãã·ã¹ãã ãWiFiå èµã®ESP32ã«äº€æããŸãããã»ãšãã©ã®ãœãããŠã§ã¢ã¯C ++ã§èšè¿°ãããŠããããç§»æ€å¯èœã§ãããçŸåšã®ããŒãã«ã®é«ããæž¬å®ããããã«äœæããtfmini-sãå«ããäž¡æ¹ã®ããã€ã¹ãPlatform.IOãšArduinoã©ã€ãã©ãªã§ ããã°ã©ã ã§ããŸãã ã ããŒãã«ãšGoogleã¹ããŒãããŒã ã®çžäºäœçšã·ã¹ãã ã®ã¢ãŒããã¯ãã£ã以äžã«ç€ºããŸããç§ãšGoogleã®ãããšãã«ã€ããŠè©±ããŸãããã
ãã®ãããBluetoothããªã³ã«ãªã£ãŠããŸãã Google SmartHomeãæäœããæ¹æ³ãçè§£ãããšããæ¥ãŸããããã®ãã¯ãããžãŒã¯ãã¹ããŒãããŒã ã¢ã¯ã·ã§ã³ã䜿çšããŠå®¶ãå¶åŸ¡ããŸãã ã圌女ã®è¡åã§è峿·±ãã®ã¯ããµãŒãã¹ãã¯ã©ã€ã¢ã³ãã§ã¯ãªãOAuth2ãµãŒããŒãšããŠæ©èœããããšã§ãããµãŒããŒã§è¡ãããäœæ¥ã®ã»ãšãã©ã¯ãHerokuã«å°éããGoogleãšç§ã®ãã¹ã¯ã®éã§ãããã·ã®ããã«éä¿¡ããOAuth2 Node.jsExpressã¢ããªã±ãŒã·ã§ã³ãå®è£ ããããšã§ããã
ç§ã¯å¹žéã§ããã2ã€ã®ã©ã€ãã©ãªã䜿çšããé©åãªãµãŒããŒå®è£ ããããŸãããæåã®ã©ã€ãã©ãªã§ããnode-oauth2-serverãããã«ãã ãŸãã Expressæ¥ç¶çšã®2çªç®ã®express-oauth-serverã©ã€ãã©ãªãããã«ãã ãŸãã
const { Pool } = require("pg");
const crypto = require("crypto");
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
module.exports.pool = pool;
module.exports.getAccessToken = (bearerToken) => {...};
module.exports.getClient = (clientId, clientSecret) => {...};
module.exports.getRefreshToken = (bearerToken) => {...};
module.exports.getUser = (email, password) => {...};
module.exports.getUserFromAccessToken = (token) => {...};
module.exports.getDevicesFromUserId = (userId) => {...};
module.exports.getDevicesByUserIdAndIds = (userId, deviceIds) => {...};
module.exports.setDeviceHeight = (userId, deviceId, newCurrentHeight) => {...};
module.exports.createUser = (email, password) => {...};
module.exports.saveToken = (token, client, user) => {...};
module.exports.saveAuthorizationCode = (code, client, user) => {...};
module.exports.getAuthorizationCode = (code) => {...};
module.exports.revokeAuthorizationCode = (code) => {...};
module.exports.revokeToken = (code) => {...};
次ã¯ãExpressã¢ããªã±ãŒã·ã§ã³èªäœã®æ§æã§ãã以äžã¯OAuthãµãŒããŒã«å¿ èŠãªãšã³ããã€ã³ãã§ãããããã§ãã¡ã€ã«å šäœãèªãããšãã§ããŸãã
const express = require("express");
const OAuth2Server = require("express-oauth-server");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const flash = require("express-flash-2");
const session = require("express-session");
const pgSession = require("connect-pg-simple")(session);
const morgan = require("morgan");
const { google_actions_app } = require("./google_actions");
const model = require("./model");
const { getVariablesForAuthorization, getQueryStringForLogin } = require("./util");
const port = process.env.PORT || 3000;
// Create an Express application.
const app = express();
app.set("view engine", "pug");
app.use(morgan("dev"));
// Add OAuth server.
app.oauth = new OAuth2Server({
model,
debug: true,
});
// Add body parser.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static("public"));
// initialize cookie-parser to allow us access the cookies stored in the browser.
app.use(cookieParser(process.env.APP_KEY));
// initialize express-session to allow us track the logged-in user across sessions.
app.use(session({...}));
app.use(flash());
// This middleware will check if user's cookie is still saved in browser and user is not set, then automatically log the user out.
// This usually happens when you stop your express server after login, your cookie still remains saved in the browser.
app.use((req, res, next) => {...});
// Post token.
app.post("/oauth/token", app.oauth.token());
// Get authorization.
app.get("/oauth/authorize", (req, res, next) => {...}, app.oauth.authorize({...}));
// Post authorization.
app.post("/oauth/authorize", function (req, res) {...});
app.get("/log-in", (req, res) => {...});
app.post("/log-in", async (req, res) => {...});
app.get("/log-out", (req, res) => {...});
app.get("/sign-up", async (req, res) => {...});
app.post("/sign-up", async (req, res) => {...});
app.post("/gaction/fulfillment", app.oauth.authenticate(), google_actions_app);
app.get('/healthz', ((req, res) => {...}));
app.listen(port, () => {
console.log(`Example app listening at port ${port}`);
});
ã³ãŒãã¯ããªããããããããŸãããèŠç¹ã説æããŸãããµãŒããŒã«äœ¿çšããã2ã€ã®OAuth2ã«ãŒãã¯ã/ oauth / tokenãš/ oauth / authorizeã§ãããããã¯ãæ°ããããŒã¯ã³ãåä¿¡ããããæéåãã®ããŒã¯ã³ãæŽæ°ãããããããã«äœ¿çšãããŸããæ¬¡ã«ããµãŒããŒãGoogleã®ã¢ã¯ã·ã§ã³ã«å¿çããããã«ããå¿ èŠããããŸãã / gaction / fulfillmentãšã³ããã€ã³ãããªããžã§ã¯ããæããŠããããšã«æ°ä»ãã§ããã
google_actions_app
ã
Googleã¯ç¹å®ã®åœ¢åŒã§ãµãŒããŒã«ãªã¯ãšã¹ããéä¿¡ãããããã®ãªã¯ãšã¹ãã®åŠçã«åœ¹ç«ã€ã©ã€ãã©ãªãæäŸããŸãã以äžã¯Googleãšã®éä¿¡ã«å¿ èŠãªæ©èœã§ããããã¡ã€ã«å šäœã¯ããã«ãããŸããæåŸã«ã/ healthzãšã³ããã€ã³ãããããŸããããã«ã€ããŠã¯ãèšäºã®æåŸã§èª¬æããŸãã
/ gaction / fulfillmentãšã³ããã€ã³ãã¯app.oauth.authenticateïŒïŒãšåŒã°ããããã«ãŠã§ã¢ã䜿çšããŸããOAuth2ãµãŒããŒãèµ·åããŠå®è¡ããããã®å€§å€ãªäœæ¥ã¯ããã®ããã«ãŠã§ã¢ãæ©èœãããããšã§ããã GoogleããæäŸããããã¢ã©ããŒã¯ã³ãæ¢åã®ãŠãŒã¶ãŒãåç §ããŠãããæå¹æéãåããŠããªãããšã確èªããŸããæ¬¡ã«ãã«ãŒãã¯èŠæ±ãšå¿çããªããžã§ã¯ãã«éä¿¡ããŸã
google_actions_app
ã
Googleã¯ç¹å®ã®åœ¢åŒã§ãµãŒããŒã«ãªã¯ãšã¹ããéä¿¡ãããããã®ãªã¯ãšã¹ãã®åæãšåŠçã«åœ¹ç«ã€ã©ã€ãã©ãªãæäŸããŸãã以äžã¯Googleã«é£çµ¡ããããã«å¿ èŠãªæ©èœã§ãããããã§ãã¡ã€ã«å šäœã衚瀺ã§ã ãŸãã
const { smarthome } = require('actions-on-google');
const mqtt = require('mqtt');
const mqtt_client = mqtt.connect(process.env.CLOUDMQTT_URL);
const model = require('./model');
const { getTokenFromHeader } = require('./util');
mqtt_client.on('connect', () => {
console.log('Connected to mqtt');
});
const updateHeight = {
"preset one": (deviceId) => {
mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "1");
},
"preset two": (deviceId) => {
mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "2");
},
"preset three": (deviceId) => {
mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "3");
},
};
const google_actions_app = smarthome({...});
google_actions_app.onSync(async (body, headers) => {...});
google_actions_app.onQuery(async (body, headers) => {...});
google_actions_app.onExecute(async (body, headers) => {...});
module.exports = { google_actions_app };
ã¹ããŒãã¢ã¯ã·ã§ã³ãGoogleã¢ã«ãŠã³ãã«è¿œå ãããšãGoogleã¯åæãªã¯ãšã¹ããçºè¡ããŸãããã®ãªã¯ãšã¹ãã«ãããã¢ã«ãŠã³ãããå©çšã§ããããã€ã¹ãç¥ãããšãã§ããŸããæ¬¡ã¯ããŒãªã³ã°ã¯ãšãªã§ããGoogleã¯ããã€ã¹ã«ã¯ãšãªãå®è¡ããŠãçŸåšã®ç¶æ ã倿ããŸãã
ã¹ããŒãããŒã ã¢ã«ãŠã³ãã«æåã«Googleã¢ã¯ã·ã§ã³ã远å ãããšãGoogleãæåã«åæãªã¯ãšã¹ããéä¿¡ããæ¬¡ã«ããŒãªã³ã°ãªã¯ãšã¹ããéä¿¡ããŠãããã€ã¹ã®å šäœåãååŸããŸããæåŸã®ãªã¯ãšã¹ãã¯ãGoogleãããã€ã¹ã«äœããããããã«æç€ºããããšãå®è¡ããããã®ãªã¯ãšã¹ãã§ãã
Googleã¹ããŒãããŒã ããã€ã¹ã®ãæ©èœãïŒç¹æ§ïŒ
Googleã¯ãããã€ã¹åºæã®æ©èœã䜿çšããŠãããã€ã¹ãå¶åŸ¡ããããã®UIèŠçŽ ãGoogleã«æäŸããé³å£°å¶åŸ¡éä¿¡ãã³ãã¬ãŒããäœæããŸããäžéšã®æ©èœã«ã¯ãColorSettingãModesãOnOffãããã³StartStopã®èšå®ãå«ãŸããŸããã¢ããªã±ãŒã·ã§ã³ã§ã©ã®æ©èœãæé©ãã倿ããã®ã«å°ãæéãããããŸããããåŸã§ã¢ãŒããéžæããŸããã
ã¢ãŒãã¯ãNåã®äºåå®çŸ©ãããå€ã®1ã€ããŸãã¯ç§ã®å Žåã¯é«ãã®ããªã»ãããéžæãããŠããããããããŠã³ãªã¹ããšèããããšãã§ããŸããã¢ãŒãã«ãé«ãããšããååãä»ããŸãããå¯èœãªå€ã¯ãããªã»ãã1ãããããªã»ãã2ãããããªã»ãã3ãã§ããããã«ãããããããGoogleããããã¹ã¯ã®é«ããããªã»ããã«èšå®ããŠãã ããããšèšã£ãŠãã¹ã¯ãå¶åŸ¡ã§ããŸããGoogleã¯ã察å¿ããå®è¡ãªã¯ãšã¹ããã·ã¹ãã ã«éä¿¡ããŸããGoogleããã€ã¹ã®æ©èœã«ã€ããŠè©³ããã¯ã ãã¡ããã芧ãã ããã
å®è¡äžã®ãããžã§ã¯ã
æåŸã«ãGoogle SmartHomeãšç§ã®ã³ã³ãã¥ãŒã¿ãŒãéä¿¡ãéå§ããŸããããã®åã¯ãngrokã䜿çšããŠExpressãµãŒããŒãããŒã«ã«ã§å®è¡ã㊠ããŸããããµãŒããŒãããããååã«æ©èœããããã«ãªã£ãã®ã§ããã€ã§ãGoogleã§å©çšã§ããããã«ããŸãããã®ãããHerokuã§ã¢ããªã±ãŒã·ã§ã³ããã¹ãããå¿ èŠããããŸããã ããã¯ãã¢ããªã±ãŒã·ã§ã³ã®å±éãšç®¡çã容æã«ããPaaSãããã€ããŒã§ãã
Herokuã®äž»ãªå©ç¹ã®1ã€ã¯ãã¢ããªã³ã¢ãŒãã§ããã¢ããªã³ã䜿çšãããšãCloudMQTTãšPostgresãµãŒããŒãã¢ããªã±ãŒã·ã§ã³ã«ç°¡åã«è¿œå ã§ããŸãã Herokuã䜿çšãããã1ã€ã®å©ç¹ã¯ãçµã¿ç«ãŠãšå±éãç°¡åãªããšã§ãã Herokuã¯ã䜿çšããŠããã³ãŒããèªåçã«æ€åºããããããã«ã/ãããã€ããŸããããã«ã€ããŠã®è©³çްã¯ãHerokuBuildpacksã«ã€ããŠèªãããšã§èŠã€ããããšãã§ããŸã ãç§ã®å Žåãã³ãŒããgit remote Herokuã«ããã·ã¥ãããã³ã«ããã¹ãŠã®ããã±ãŒãžãã€ã³ã¹ããŒã«ããããã¹ãŠã®éçºäŸåé¢ä¿ãåé€ãããã¢ããªã±ãŒã·ã§ã³ããããã€ãããŸãããããã¯ãã¹ãŠãåçŽãªãgit pushherokumainãã³ãã³ãã§å®è¡ãããŸãã
æ°åã¯ãªãã¯ããã ãã§ãCloudMQTTãšPostgresãã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšã§ãããããã®ãµãŒãã¹ãã¢ããªã±ãŒã·ã§ã³ãšçµ±åããããã«å¿ èŠãªç°å¢å€æ°ã¯ãããã§ãããããã¯ã¯ãéãèŠæ±ããªãã£ãããã ããCloudMQTTã¯ãæé¡5ãã«ã®ãµãŒãããŒãã£ã®ã¢ããªã³ã§ãã
Postgresã®å¿ èŠæ§ã¯èªæã ãšæããŸãããCloudMQTTã¯ãã£ãšæ³šç®ã«å€ããŸãã
ã€ã³ã¿ãŒããããããã©ã€ããŒããããã¯ãŒã¯ãžãé£ããæ¹æ³
ã¢ããªã±ãŒã·ã§ã³ããŸãã¯ç§ã®å Žåã¯IoTããã€ã¹ãžã®ã¢ã¯ã»ã¹ãæäŸããæ¹æ³ã¯ããã€ããããŸãã 1ã€ç®ã¯ãããŒã ãããã¯ãŒã¯ã®ããŒããéããŠãããã€ã¹ãã€ã³ã¿ãŒãããã«æ¥ç¶ããããšã§ãããã®å ŽåãHeroku Expressã¢ããªã¯ããããªãã¯IPã¢ãã¬ã¹ã䜿çšããŠããã€ã¹ã«ãªã¯ãšã¹ããéä¿¡ããŸããããã«ã¯ãESP32ã®éçIPã ãã§ãªããããªãã¯éçIPãå¿ èŠã«ãªããŸãã ESP32ã¯HTTPãµãŒããŒãšããŠãæ©èœããHerokuããã®æç€ºãåžžã«ãªãã¹ã³ããå¿ èŠããããŸããããã¯ã1æ¥ã«æ°ååœä»€ãåä¿¡ããããã€ã¹ã«ãšã£ãŠå€§ããªãªãŒããŒãããã§ãã
2çªç®ã®æ¹æ³ã¯ãããŒã«ãã³ãããšåŒã°ããŸããããã䜿çšãããšããµãŒãããŒãã£ã®å€éšãµãŒããŒã䜿çšããŠãããŒã転éãå¿ èŠãšããã«ããã€ã¹ãã€ã³ã¿ãŒãããã«ã¢ã¯ã»ã¹ã§ããŸããããã€ã¹ã¯åºæ¬çã«ãéããŠããããŒããèšå®ãããµãŒããŒã«æ¥ç¶ããŸããæ¬¡ã«ãå€éšãµãŒããŒããéããŠããããŒããååŸããããšã«ãããå¥ã®ãµãŒãã¹ãããã¯ãšã³ãã«çŽæ¥æ¥ç¶ã§ããŸããæåŸã«ããã®éããŠããããŒãã䜿çšããŠããã€ã¹ã«çŽæ¥æ¥ç¶ããŸããã¢ãããŒãã¯å®å šã«æ£ããå Žåãšããã§ãªãå ŽåããããŸããç§ã¯ããã«é¢ããèšäºã®äžéšããèªãã§ããŸããã
ããŒã«ãã³ãã®å éšã§ã¯å€ãã®ããšãèµ·ãã£ãŠãããäœãèµ·ãã£ãŠããã®ãå®å šã«ã¯çè§£ããŠããŸããããã ããèå³ãããå Žåã¯ã詳现ã説æããè峿·±ãèšäºãããã€ããããŸããããŒã«ãã³ããããããçè§£ããããã«ç§ãèªãã 2ã€ã®èšäºããããŸãïŒ ãŠã£ãããã£ã¢ãã㊠ãã©ã€ã¢ã³ã»ãã©ãŒããã«ããMITããã®èšäºã
ã€ã³ã¿ãŒãããããIoTçµç±ã®ãã©ã€ããŒããããã¯ãŒã¯ãž
ç§ã¯ãããã®è§£æ±ºçã«ããŸãæºè¶³ããŠããŸããã§ãããããããã®ã¹ããŒãããã€ã¹ãèªå® ã«æ¥ç¶ããŸããããã«ãŒã¿ãŒã§ããŒããéãå¿ èŠããªãã£ããããããŒã転éã¯ãããŸããã§ããããŸãã穎ãéããã®ã¯ç§ãæ¢ããŠãããã®ããã¯ããã«é£ããããã§ãP2Pãããã¯ãŒã¯ã«é©ããŠããŸãããããªã調æ»ã®çµæãMQTTãçºèŠãããããIoTã®ãããã³ã«ã§ããããšãç¥ããŸãããäœæ¶è²»é»åãæ§æå¯èœãªéå®³èæ§ãªã©ã®ããã€ãã®å©ç¹ããããããŒã転éãå¿ èŠãšããŸãããMQTTã¯ãããªãã·ã£ãŒ/ãµãã¹ã¯ã©ã€ããŒãããã³ã«ã§ããã€ãŸããããŒãã«ã¯ç¹å®ã®ãããã¯ã®ãµãã¹ã¯ã©ã€ããŒã§ãããHerokuã¢ããªã±ãŒã·ã§ã³ã¯ãã®ãããã¯ã®ãããªãã·ã£ãŒã§ãã
ãã®ãããGoogleã¯Herokuã«é£çµ¡ãããã®ãªã¯ãšã¹ããåæããŠããªã¯ãšã¹ããããããã€ã¹ãšãã®æ°ããç¶æ ãŸãã¯ã¢ãŒããå€å¥ããŸããæ¬¡ã«ãHerokuã¢ããªã¯ãHerokuãžã®ã¢ããªã³ãšããŠãããã€ãããCloudMQTTãµãŒããŒã«ã¡ãã»ãŒãžãå ¬éããããŒãã«ã«æ°ããããªã»ããã«ç§»åããããã«æç€ºããŸããæåŸã«ãããŒãã«ã¯ãããã¯ããµãã¹ã¯ã©ã€ãããHerokuã¢ããªã«ãã£ãŠæçš¿ãããã¡ãã»ãŒãžãåä¿¡ããŸããæåŸã«ãããŒãã«ã¯èŠæ±ã«å¿ããŠé«ãã調æŽããŸãã googleactionsappãã¡ã€ã«ã«ã¯ãç¹å®ã®ããã€ã¹IDã«å¯ŸããŠ1ã€ã®MQTTçªå·ãå ¬éããupdateHeight颿°ãããããšãããããŸããããã¯ãHerokuã¢ããªã±ãŒã·ã§ã³ãããŒãã«ç§»åèŠæ±ãMQTTã«å ¬éããæ¹æ³ã§ãã
æåŸã®ã¹ãããã¯ãESP32ã§ã¡ãã»ãŒãžãåä¿¡ããããŒãã«ãç§»åããããšã§ãã以äžã®ããŒãã«ã³ãŒãã®ãã€ã©ã€ãã®ããã€ãã玹ä»ããŸãããã¹ãŠã®ãœãŒã¹ã³ãŒãã¯ããã«ãã ãŸãã
void setup()
{
Serial.begin(115200);
...
tfminis.begin(&Serial2);
tfminis.setFrameRate(0);
...
state_machine = new StateMachine();
state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL);
setup_wifi();
client.setServer(MQTT_SERVER_DOMAIN, MQTT_SERVER_PORT);
client.setCallback(callback);
...
}
ããŒãã«ãããŒãããããšãæåã«TFMini-SïŒè·é¢ã»ã³ãµãŒïŒéã®éä¿¡ãéå§ããŠãçŸåšã®ããŒãã«ã®é«ããååŸããŸããæ¬¡ã«ãããŒãã«ç§»åçšã®ã¹ããŒããã·ã³ãã»ããã¢ããããŸããã¹ããŒããã·ã³ã¯MQTTãä»ããŠã³ãã³ããåä¿¡ãããŠãŒã¶ãŒã®èŠæ±ãè·é¢ã»ã³ãµãŒã«ãã£ãŠèªã¿åãããå®éã®ããŒãã«ã®é«ãã«äžèŽããã圹å²ãæãããŸããæåŸã«ãWi-Fiãããã¯ãŒã¯ã«æ¥ç¶ããMQTTãµãŒããŒã«æ¥ç¶ããŠããµãã¹ã¯ã©ã€ãããŠããMQTTãããã¯ã§åä¿¡ããããŒã¿ã®ã³ãŒã«ããã¯ãèšå®ããŸãã以äžã«ãã³ãŒã«ããã¯é¢æ°ã瀺ããŸãã
void callback(char *topic, byte *message, unsigned int length)
{
...
String messageTemp;
for (int i = 0; i < length; i++)
{
messageTemp += (char)message[i];
}
if (messageTemp == "1") {
state_machine->requestStateChange(ADJUST_TO_PRESET_1_HEIGHT_STATE);
}
if (messageTemp == "2") {
state_machine->requestStateChange(ADJUST_TO_PRESET_2_HEIGHT_STATE);
}
if (messageTemp == "3") {
state_machine->requestStateChange(ADJUST_TO_PRESET_3_HEIGHT_STATE);
}
...
}
ã¹ããŒããã·ã³ã¯ãMQTTãããã¯ã§åä¿¡ããç¶æ 倿Žãç»é²ããŸããæ¬¡ã«ãã¡ã€ã³ã«ãŒãã§æ°ããç¶æ ãåŠçããŸãã
void loop()
{
if (!client.connected())
{
reconnect();
}
client.loop();
state_machine->processCurrentState();
}
ã¡ã€ã³ã«ãŒãã¯ããã€ãã®ããšãè¡ããŸããæåã«ããŸã æ¥ç¶ãããŠããªãå Žåã¯MQTTãµãŒããŒã«åæ¥ç¶ããŸããæ¬¡ã«ãMQTTãããã¯ãéããŠåä¿¡ãããã¹ãŠã®ããŒã¿ãåŠçããŸããæåŸã«ãã³ãŒãã¯ãããŒãã«ããããMQTTãããã¯ã§èŠæ±ãããç®çã®å Žæã«ç§»åããããšã«ãã£ãŠæ©èœããŸãã
ããã§å šéšã§ãïŒããŒãã«ã¯å®å šã«é³å£°å¶åŸ¡ãããŠãããã³ãã³ããåä¿¡ããããã«Googleãšéä¿¡ããŸãã
æè¿ã®ã¡ã¢
ç§ãèšåããªãã£ãæåŸã®ãšã³ããã€ã³ãã¯/ healthzãšã³ããã€ã³ãã§ããããã¯ãGoogleãããªãè¿ éãªå¿çãæåŸ ããŠããããã§ãããç§ã®å Žåããã¹ãŠã®ãªã¯ãšã¹ãã§Herokuã¢ããªãããŒãããããšã¯ã§ããŸããã / healthzãšã³ããã€ã³ãã«æ¯åpingãå®è¡ããããã«pingãµãŒãã¹ãèšå®ããŠããµãŒãã¹ãæ£åžžã«ä¿ã¡ãå¿çã§ããããã«ããŸããããã®ãããªããšãèšç»ããŠããå Žåã¯ãããŒã¹ã§ã®ãã¹ãŠã®ç¡ææéãããã«è²»ããããããšãå¿ããªãã§ãã ãããããã§ãã¹ãŠãæ£åžžã«ãªããŸãããããã¯Herokuã§äœ¿çšãããå¯äžã®ã¢ããªã±ãŒã·ã§ã³ã§ããããã«ãæé¡7ãã«ã§ãã¢ããªãå®è¡ãç¶ããHerokuã®ãããŒãã©ã³ã«ã¢ããã°ã¬ãŒãã§ããŸã ã
IoTããã€ã¹ã®æ§ç¯ã«ã¯ãæåã¯å€ãã®ãªãŒããŒãããã䌎ããŸããããŒããŠã§ã¢ãèšèšããå¶åŸ¡ã¹ããŒã ãæ§ç¯ããMQTTãµãŒããŒãæ§æããExpress OAuth2ãµãŒããŒãäœæããã¢ã¯ã·ã§ã³ãéããŠGoogle SmartHomeãšå¯Ÿè©±ããæ¹æ³ãåŠã³ãŸãããæåã®ãªãŒããŒãããã¯å€§ããã£ãã§ãããç§ã¯ããããã®ããšãæãéãããããªæ°ãããŸãïŒèšããŸã§ããªããMQTTãµãŒããŒãExpress OAuth2ã¢ããªã±ãŒã·ã§ã³ãµãŒããŒãããã³Googleã¹ããŒãããŒã ã¢ã¯ã·ã§ã³ã¯ãå¥ã®ãããžã§ã¯ãã«äœ¿çšã§ããŸããç§ã¯ã¹ããŒãããŒã ã«èå³ããããIoTããã€ã¹ã®ã¬ããŒããªãŒãæ¡å€§ããŠãå®¶ã®åšãã§èµ·ãã£ãŠããããšã远跡ããMQTTãä»ããŠå ±åããã»ã³ãµãŒãå«ããããšãã§ããŸããåå£ã枩床ãå ã®ã»ã³ãµãŒãç£èŠããããã®ã»ã³ãµãŒã¯ãç£èŠãšåæã«éåžžã«è峿·±ããã®ã«ãªããŸãã
次ã¯äœã§ããïŒ
ã«ãŠã³ã¿ãŒãããã®é«ãã¯ãããããä¿¡é Œæ§ã®äœãæ¹æ³ã§æž¬å®ãããããã«ãªããŸãããç§ã¯äžè¬çã«åäœããèµ€å€ç·è·é¢ã»ã³ãµãŒTFMini-Sã䜿çšããŠããŸããéšå±ã®åšå²ã®ç §æãå€åããæ¥äžãããŒãã«ã®é«ãããããã«å€åããããšã«æ°ã¥ããŸãããããŒãã«ãéããããã®å転æ°ãã«ãŠã³ãããå転è§åºŠã»ã³ãµãŒã泚æããŸãããããã«ããã1æ¥äžãã€ã§ãããæ£ç¢ºãªåããåŸãããã¯ãã§ããå°äžã§ãã¹ãããŠãããµãŒããŒã«ãã¢ã¯ã»ã¹ã§ããŸãããã®äžã§ãèªåã§äœãããã¹ããããå Žåã¯ãèªåã®Mosquitto MQTTãµãŒããŒã Node-REDãããã³ExpressOAuth2ã¢ããªã±ãŒã·ã§ã³ãæ¢çŽ¢ã§ããŸããæåŸã«ããã¹ãŠã®é»åæ©åšãç§ã®æºã®äžã«ãããŸãããã¹ãŠããããã«ãªãããã«ããã€ã¹ãæŽçããäºå®ã§ãïŒ
èšäºãèªãã§ãããŠããããšãïŒäŸ¿å®äžããã¹ãŠã®ãªã³ã¯ã瀺ããŸãã
- Torque Calculator
- 90 degree right angle gear box
- BLE Terminal
- Platform.IO
- TFMini-S Arduino Driver
- Google Smart Home Actions
- Node OAuth2 Server
- Express OAuth2 Server
- ESP32 IoT Desk Server model.js
- ESP32 IoT Desk Server index.js
- ESP32 IoT Desk Server google_actions.js
- Google Smart Home Device Traits
- NGROK
- ESP32 IoT Desk Firmware
- Node-RED
- Heroku
- Heroku Hobby Plan
- Heroku Buildpacks
- Wikipedia Hole Punching
- MIT Paper on Hole Punching by Bryan Ford et al.