Linux MQTT i inne usługi jakich używam do IoT

Programowanie w językach: C , C++, python, oraz skrypty bash , tcsh
wszystko co lubią open-sourcowcy .... pod konsolą i open gl
Regulamin forum
Przy pisaniu nowego tematu podajemy język w formacie:

[C] , [C++] , [Python] , [BASH] , [TCSH]
ODPOWIEDZ
Awatar użytkownika
squeez
GRafik
Posty: 150
Rejestracja: 16 paź 2017, 23:52

Linux MQTT i inne usługi jakich używam do IoT

Post autor: squeez »

Powstał dział to może tak po krotce opiszę jak ja u siebie zaprzęgam orange pi zero z linuxem do usług IoT.
Wszelkiej maści sensory/sterowniki to nic innego jak kochane (prawie przez wszystkich) ESP8266 z biblioteką JSON i MQTT.

Na serwerze jest broker MQTT chyba najpopularniejszy mosqiuto. Serwer www nginx, parser PHP w wersji 7 oraz baza danych sqlite.
Dobór ie przypadkowy, ze względu na lekkość rozwiązań. Nginx zamiast tłustego apache, sqlite (szybki i lekki) zamiast słonia MySQL a teraz raczej MariaDB.

W szczegóły protokołu nie będę wchodził bo pewnie każdy wie co i jak, ja opiszę jak to połączyłem w swoim przypadku żeby zamiast klepać apki na dupodroida czy szajsfona (w moim gospodarstwie domowy używane są i jedne i drugie dlatego zdecydowałem się że aplikacja do sterowania będzie serwowane przez orangepi w formie aplikacji internetowej (HTML+PHP+SQL) przez co dostępna jest na każdym urządzeniu mającym przeglądarkę www.

Na temat budowy stron też nie będę pisał, ja mam swój framewrok, który napisałem kilka lat temu i cały czas go rozwijam, ale to nie ważne bo można sobie napisać w jednym pliku, pomięszać PHP z HTML i CSS itp. i też będie chodzić. U mnie jest rodzielenie logiki od widoku i podział na moduły.

Jak już wszytko zainstalowałem (apt-get install ...) pora to połączyć.

Do odbieranie danych po MQTT z czujników wykorzystałem klienta mosquito (mosquitto_sub - do subskrypcji, mosquitto_pub - można publikować).

Skrypt umieszczony w /etc/init.d pozwala na przekierowanie tego co przychodzi na interesujący nas topic do skryptu PHP który podejmie odpowiednie działania, co i jak wyjaśnię niżej.

Kod: Zaznacz cały

#!/bin/sh
### BEGIN INIT INFO
# Provides:             mqttphp
# Required-Start:       $all
# Required-Stop:        $remote_fs $syslog
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    MQTT service
# Description:
#  Transport (MQTT) to PHP and sqlite.
### END INIT INFO

SERVERIP=192.168.5.9
DAEMON=/usr/bin/mosquitto_sub
MQTT_TOPIC=mqtt/\#
PHPSCRIPT=/var/www/iHome/mqtt/mosquitto.php
PID_FILE=/var/run/mqttphp.pid

test -x $DAEMON || exit 0

mqtt_start() {

        echo "Start nasluchu ..."
        rm $PID_FILE
        touch $PID_FILE
        echo $$ > $PID_FILE
        $DAEMON -v -t $MQTT_TOPIC -h $SERVERIP |
        while IFS= read -r line
        do
                /usr/bin/php7.0 $PHPSCRIPT $line
        done
}


case "$1" in
        start)
                mqtt_start
        ;;

        stop)
        echo "Stop nasluchu ...\n\r"
        for child in $(ps -o pid,ppid -ax | awk "{ if ( \$2 == $(cat $PID_FILE) ) { print \$1 }}")
        do
                kill $child
                echo $child
        done
                ;;
esac

exit 0
na początku mamy kila ementów do konfiguracji:
SERVERIP=192.168.5.9
DAEMON=/usr/bin/mosquitto_sub
MQTT_TOPIC=mqtt/\#
PHPSCRIPT=/var/www/iHome/mqtt/mosquitto.php
PID_FILE=/var/run/mqttphp.pid

czyli adres IP brokera MQTT w moim przypadku taki sam jak orange pi, dalej położenie binarki w systemi plików, MQTT_TOPIC to co chcemy subskybować, na końcu jest hasz czyli wszytko co przyjdzie na topic mqtt będzie przetwarzane, czyli np. mqtt/sensors albo mqtt/alram/lazienka itp. itd. PHPSCRIPT to ścieżka do skryptu PHP jaki to będzie przetwarzał, PID_FILE miejsce pliku w którym będzie ID procesu, potrzebne mi to było do testowania a potem uśmieracnia procesu jak zajdzie taka potrzeba.

Czarną robotę rodzi ten fragment kodu:

Kod: Zaznacz cały

$DAEMON -v -t $MQTT_TOPIC -h $SERVERIP |
        while IFS= read -r line
        do
                /usr/bin/php7.0 $PHPSCRIPT $line
        done
powoduje przekazanie każdej linii textu jaka się pojawi w danym temacie co skryptu PHP, tu taka mał uwaga w swoich aplikacjach na ESP trzeba zadbać by dane były wysyłane w jednej linii, standardowo biblioteka JSON z jakiej korzystam formatowała kod żeby ładnej wyglądał dla oka ale drętwo działa bo rozbija na kilka linii i musiałem to zmienić.

Teraz wkracza PHP.
Nie będę pokazywał całości bo to nie jest projekt opensource i jest wykorzystywany komercyjnie. Ale idea jest taka:
Jest klasa nadrzędna którą dziedziczą dzieci, kądy moduł to dziecko klasy nadrzędnej. W tej głównej klasie konfigurowane są wszystkie zasoby, jak baza danych, zmienne środkowiskowe, obsługa sesji itp. po czym na podstawie adresu podejmowana jest decyzja jaki moduł ma być uruchomiony.

Czyli to co przychodzi na do brokera w postaci JSON na topic nqtt/sensors/set/{idx:1,type:"ds18b20",id_value:"28XXYYZZ",value:2500}

Uruchamia moduł sensors, wywoływana jest akcja sety i przekazuje parametry.

Plik sensors jest bardzo prosty:

Kod: Zaznacz cały

<?php
include(PATH.'/mqtt/modules/mainclass.php');
class sensors extends MainClass
{
        public function __construct() {
                parent::__construct(get_class($this));
        }

        public function _default() {

        }

        public function set() {
                $this->sql->query("INSERT INTO sensors (idx, type, id_value, value) VALUES(".$this->json['IDX'].", '".$this->json['type']."', '".$this->json['ID']."', ".$this->json['value'].")");
        }
}
?>
W klasie jest metoda set która nie robi nic innego jak zapisuje do bazy dane. zmienna json jest ustawiana w klasie rodzicu mainclass.php
tam wygląda to równie banalnie:

Kod: Zaznacz cały

abstract class MainClass {
....
protected       $msg = '';
protected       $json = null;
.....

         // Konstruktor
        public function __construct($className = '') {
                $this->sql = sqlib::singleton();
                $this->className = &$className;
        }

        public function msg($msg) {
                $this->msg = &$msg;
                $this->json = json_decode( $msg, true );
        }
.....
}
W taki sposób można zapisywać czy też odczytywać z bazy wszelkiej maści informacje jakie chcemy. Ja wymyśliłem sobie że dane z czujników trafiają do jednej tabeli gdzie pola IDX - to unikalny id modułu z ESP, type - to wartość tekstowa typu czujnika (tak żeby można była potem wyciągać czy chemy temp. ciśnienie czy co tam innego. id_value to identyfikator cujnika w przypadku DS18B20 to unikalny ID każdego czujnika, i value to wartość temp. w tabeli jest jeszcze pole datatimne wypełniane automatcyznie aktualną datą i czasem.

Do łatwiejszego zarządzania bazą danych wykorzystany projekt https://www.phpliteadmin.org/ w sumie dwa pliki umieszczone na serwerze i przez przeglądarkę konfigurujemy co trzeba.

W drugą stronę czyli jak my chcemy coś zadać modułom czyli z poziomu PHP wysłać coś po MQTT do czujników wykorzysuję klasę phpMQTT (https://github.com/bluerhinos/phpMQTT).

Aplikacja do obsługi (warstwa widoku) wykorzystuje jQuery mobile (https://jquerymobile.com/) można łatwo i fajnie tworzyć "lekkie" interfejsy dla urządzeń mobilnych.

Tak mniej więcej to działa, jak ktoś ma jakieś pytania, sugestie itp. w miarę możliwości postaram się odpowiedzieć.

PS. zamieszczone kody maja charakter poglądowy, pochodzą z testowej maszyny (w tej chwili mam tylko do niej dostęp) i mogę się nico różnić od tych pracujących aktualnie.
Awatar użytkownika
squeez
GRafik
Posty: 150
Rejestracja: 16 paź 2017, 23:52

Re: Linux MQTT i inne usługi jakich używam do IoT

Post autor: squeez »

PS2. dane jakie trafiaja do bazy nie są validowane co jest błędem ale w tym przypadku aplikacja działa lokalnie więc sobie to podarowałem, żona raczej nie będzie chciała mi zrobić kuku :) ale jeśli ktoś miałby się tym sugerować to przy publicznie wystawionych usługach, wszystko co przyjdzie musi być sprawdzane/rzutowane na typy.
Awatar użytkownika
SunRiver
Użytkownik
Posty: 948
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

Re: Linux MQTT i inne usługi jakich używam do IoT

Post autor: SunRiver »

Nic nie jest doskonałe panie kolego ... :)
ale jest i trzeba tak jak jest przyjmować niektóre rzeczy ....
Awatar użytkownika
SunRiver
Użytkownik
Posty: 948
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

Re: Linux MQTT i inne usługi jakich używam do IoT

Post autor: SunRiver »

Dzięki Squeez za wpis :)
Natchnęło mnie to nieco i znalazłem zastosowanie dla jednego z sbcków ...
khadas obecnie robi za brokera mosquitto ...
Wnioski zadawalające opisałem tu : https://suniotprojects.blogspot.com/
Awatar użytkownika
flasher
Użytkownik
Posty: 11
Rejestracja: 22 lis 2017, 16:23
Kontakt:

Re: Linux MQTT i inne usługi jakich używam do IoT

Post autor: flasher »

public function set() {
$this->sql->query("INSERT INTO sensors (idx, type, id_value, value) VALUES(".$this->json['IDX'].", '".$this->json['type']."', '".$this->json['ID']."', ".$this->json['value'].")");
}
Ten kod jest niebezpieczny.
AVR -> STM32 -> FPGA (Xilinx) <3
Awatar użytkownika
squeez
GRafik
Posty: 150
Rejestracja: 16 paź 2017, 23:52

Re: Linux MQTT i inne usługi jakich używam do IoT

Post autor: squeez »

teraz dopiero zauważyłem odpowiedź, a czemu jest "niebezpieczny" :D

bo w zapytanie wstawiam dane wprost z JSON-a?

Jeżeli tak to: dane trafiają tam z MQTT do którego trzeba się zalogować (znać login i hasło), biega to po WiFi z WPA2 i dość długim niesłownikowym hasłem.

Fakt można dorobić do tego walidację danych, albo jeszcze lepiej skorzystać z metody prepare() w której samo PDO zadba o poprawną walidację danych. Jednak jak wspomniałem wyżej SQL Injection w tym przypadku byłby najmniejszym problemem (jeśli ktoś już by się dostał do sieci WiFI).
ODPOWIEDZ

Wróć do „Linux”