Cześć,
Od kilku lat dłubię sobie frameworka internetu rzeczy, który napędza mi w domu całe rozwiązania typu smarthome. Ostatnimi czasy zbudowałem bramkę do Zigbee, która też napędzana jest owym frameworkiem.
Na początku wspierałem ESP8266, potem też ESP32. Pod spodem jest Arduino core a całość działa w oparciu o PlatformIO. Dążę do eliminacji Arduino, jednak w przypadku ESP8266 to bardzo trudne zadanie, bo będzie wymagać przygotowania własnej paczki platformy (to co jest w rejestrach to średniowieczne wersje ~1.5, a ostatnia to 3.4).
Funkcje
- zdecydowałem na wstępie, że chciałbym pójść w kierunku kompzycji, realizowanej na wzór... Unity3D
- głównym obiektem jest rotator aplikacji, który tworzony jest na starcie aplikacji
- rotator posiada listę aplikacji, które są instancjonowane i wykonywane do końca - po zakończeniu aplikacji wstaje następna a na koniec się to zapętla
- zwykle oprogramowanie urządzenia składa się z aplikacji funkcjonalnej (zachowanie urządzenia) oraz konfiguracyjnej (własny access point)
- mając wskaźnik do aplikacji możemy wyszukiwać komponenty po typie i w łatwy sposób unikać sztywnych referencji
- komponenty można dodawać i usuwać w trakcie działania aplikacji a stosując mechanizm lock i weak_ptr pisać stabilny i bezpieczny kod
Komponenty
Poza samym szkieletem, użytkownik może korzystać z komponentów wewnętrznych, jak i swoich własnych. Wśród komponentów wewnętrznych, mamy takie jak:
- portal urządzenia po HTTP w sieci lokalnej, z terminalem, statusem a także możliwością aktualizacji oprogramowania
- komponent połączenia MQTT
- komponenty konfiguracji (dostawcy oraz nadrzędny)
- komponent wysyłający statystyki urządzenia (RSSI, IP i inne)
- komponent realizujący różne funkcje przycisku RESET
Moje urządzenia
Na bazie frameworka zbudowałem kilka swoich urządzeń, niektóre są open source:
- PelletMon - zarządzanie kotłem grzewczym po CAN/CanOpen ( https://hackaday.io/project/176557-pelletmon-iot-for-central-heating-boiler )
- RaespGateway - bramka WiFi na 433MHz do sterowania gniazdami ( https://hackaday.io/project/185280-raesp-gateway )
- EnergyMonitor - monitor energii elektrycznej oparty o czujnik odbiciowy zliczający obroty tarczy ( https://hackaday.io/project/175653-iot-for-old-energy-meter )
- KSZigbeeGateway - wspomniana wcześniej bramka Zigbee, z głośnikiem do powiadomień ( https://hackaday.io/project/194721-ks-zigbee-gateway )
Fragmenty kodu
/*
Budowanie listy komponentów, inicjalizacja aplikacji.
*/
bool EnergyMonitorApp::init()
{
/* Add WiFi connector component. */
addComponent<ksf::comps::ksWifiConnector>(apps::config::EnergyMonitorConfig::emonDeviceName);
/* Add MQTT components. */
auto mqttWp{addComponent<ksf::comps::ksMqttConnector>()};
addComponent<ksf::comps::ksDevStatMqttReporter>();
/* Add LED indicator components. */
statusLedWp = addComponent<ksf::comps::ksLed>(STATUS_LED_PIN);
eventLedWp = addComponent<ksf::comps::ksLed>(EVENT_LED_PIN);
/* Create Device Portal component. */
addComponent<ksf::comps::ksDevicePortal>();
/* Add sensor component. */
auto sensorCompWp{addComponent<components::EnergySensor>(ANA_PIN)};
/* Setup reset button. */
addComponent<ksf::comps::ksResetButton>(CFG_PUSH_PIN, LOW);
/* Bind MQTT connect/disconnect events for LED status. */
if (auto mqttSp{mqttWp.lock()})
{
mqttSp->onConnected->registerEvent(connEventHandleSp, std::bind(&EnergyMonitorApp::onMqttConnected, this));
mqttSp->onDisconnected->registerEvent(disEventHandleSp, std::bind(&EnergyMonitorApp::onMqttDisconnected, this));
}
/* Set event LED. */
if (auto sensorCompSp{sensorCompWp.lock()})
sensorCompSp->setEventLed(eventLedWp);
/* Start blinking status LED. */
if (auto statusLedSp{statusLedWp.lock()})
statusLedSp->setBlinking(500);
return true;
}
/*
Etap post-inicjalizacji. To miejsce w którym można wyszukiwać komponenty w aplikacji.
Dzięki temu możemy wyszukać np. komponent MQTT i zarejestrować callback reagujący na zdarzenie.
*/
bool AudioPlay::postInit(ksf::ksApplication* app)
{
using namespace std::placeholders;
if (mqttWp = app->findComponent<ksf::comps::ksMqttConnector>(); auto mqttSp{mqttWp.lock()})
{
mqttSp->onDeviceMessage->registerEvent(msgEventHandleSp, std::bind(&AudioPlay::onMqttDevMessage, this, _1, _2));
mqttSp->onConnected->registerEvent(connEventHandleSp, std::bind(&AudioPlay::onMqttConnected, this));
}
return true;
}
/*
Obsługa wiadomości TTS. Najpierw parsujemy a potem dodajemy do playlisty efekt dźwiękowy, po którym
zostanie odtworzona wiadomość głosowa. Podobnie jak zapowiadanie pociągu na stacji PKP :)
*/
void AudioPlay::onMqttDevMessage(const std::string_view& topic, const std::string_view& payload)
{
if (payload.empty())
return;
std::string_view flashFileName;
if (topic == PSTR("info"))
flashFileName = PSTR("/info.mp3");
else if (topic == PSTR("alarm"))
flashFileName = PSTR("/alarm.mp3");
else
return;
std::string_view languagePayload;
std::string_view textPayload;
if (payload.size() > 3 && payload[2] == ':')
{
languagePayload = payload.substr(0, 2);
textPayload = payload.substr(3);
}
else
{
languagePayload = PSTR("en");
textPayload = payload;
}
if (!flashFileName.empty())
enqueueAudioCommand<PlayFromFlashCommand>(std::string(flashFileName));
enqueueAudioCommand<TextToSpeechCommand>(std::string(textPayload), std::string(languagePayload));
}
Galeria
Linki
- https://github.com/cziter15/ksIotFrameworkLib
- https://hackaday.io/project/185783-iot-framework-for-arduino-esp328266
Dajcie znać, co sądzicie