Ostatnie zmiany:
07-11-2017: Przykłady pobierania danych z zaawansowanych stacji, Integracja ze Open-Smog, promocja na czujnik
20-12-2017: Kontrola zasilania USB na Raspberry Pi 3, dzięki czytelnikowi
03-02-2018: Nowe API od GIOŚ Poland
08-02-2018: Odnajdywanie ID
SMOG stał się nieodłączną częścią życia w dużych miastach. Postarajmy się więc zbudować wiarygodny, własny czujnik SMOGu – na początek cząsteczek o wielkości 2,5 oraz 10 μm. Pewnym problemem staje się wybór czujnika, ponieważ niełatwo znaleźć taki, który łączy w sobie długą żywotność i precyzję pomiaru z przystępną ceną. W końcu – po zasięgnięciu opinii – zdecydowałem się na czujnik cząsteczek – Nova Fitness SDS011:
Urządzenie podłączamy możliwie krótkim (kilka cm) wężykiem, tak aby wlot pobierał z zewnątrz powietrze. Długi wężyk – 100cm jak na pierwszym zdjęciu – znacznie obniża rezultaty – zaniża pomiar.
Pamiętajmy także, że czujnik pracuje cały czas, więc być może warto spróbować załączać go tylko na czas pomiaru. W wersji pracującej u mnie – wybrałem dość proste rozwiązanie – wyłączam zasilanie po pomiarze, a przed pomiarem – załączam i czekam 60 sekund.
Kolejna ważna kwestia – czujnik staje się niewiarygodny, gdy wilgotność przekracza 70%, pamiętajmy o tym!
Najpierw zainstalujmy bc – potrzebny do obliczeń:
apt update
apt upgrade
apt install bc git
Nie zapominajmy, że to pierwsza wersja naszego czujnika – i jak się domyślacie – będziemy modyfikować go pod kątem pomiarów wilgotności.
Komunikacja z urządzeniem jest bardzo prosta – po umieszczeniu w porcie USB otrzymujemy /dev/ttyUSB0 – z którego czytamy tak samo jak z innego interfejsu szeregowego:
/bin/stty -F /dev/ttyUSB0 9600 raw
/usr/bin/od --endian=big -x -N10 < /dev/ttyUSB0
Po odczytaniu – sprawdzamy czy linia zaczyna się od „aac0”. Dane podawane szesnastkowo, little endian – a więc finalną wartość należy wyliczyć. Cały kod, łącznie z aktualizowaniem bazy Influx do rysowania w Grafanie przedstawia się następująco, mam nadzieję, że jest niezwykle przejrzysty:
#!/bin/bash
# Czytnik z SDS011, zakładamy port szeregowy na /dev/ttyUSB0
# Bazuje na: http://kuehnast.com/s9y/archives/633-Feinstaubmessung_mit_dem_Raspberry_Pi.html
# [email protected], 2017, NO WARRANTY, GPL v2
#
# Zmienne - jeśli trzeba należy zmienić
serial_port="/dev/ttyUSB0"
#Włączamy port USB - zasilanie - dotyczy WYŁĄCZNIE Orange Pi (A20)
/usr/bin/sunxi-pio -m PH26''
#Czekamy aż załączy się wentylator i ustablizuje przepływ powietrza
sleep 60
#Główny program
#Ustawiamy tryb portu szeregowego
/bin/stty -F $serial_port 9600 raw
#Czytamy dane - big-endian, szenastkowe
RAW_DATA=`/usr/bin/od --endian=big -x -N10 < /dev/ttyUSB0 | /usr/bin/head -n 1 | /usr/bin/cut -f2-10 -d" "`
HEADER=`echo $RAW_DATA | /usr/bin/awk '{print $1}'`
#Probe for propper header
if [ "$HEADER" = "aac0" ];
then
#Let us cut the RAW DATA and put it into variables - data is in hexadecimals
HEX_PPM25_L=$(echo $RAW_DATA|cut -f2 -d " "|cut -b1-2);
HEX_PPM25_H=$(echo $RAW_DATA|cut -f2 -d " "|cut -b3-4);
HEX_PPM10_L=$(echo $RAW_DATA|cut -f3 -d " "|cut -b1-2);
HEX_PPM10_H=$(echo $RAW_DATA|cut -f3 -d " "|cut -b3-4);
#Convert variables to decimals
PPM25_L=$(echo $((0x$HEX_PPM25_L)));
PPM25_H=$(echo $((0x$HEX_PPM25_H)));
PPM10_L=$(echo $((0x$HEX_PPM10_L)));
PPM10_H=$(echo $((0x$HEX_PPM10_H)));
#More simple math
PPM25=`echo "((${PPM25_H}*256)+${PPM25_L})/10" | bc`
PPM10=`echo "((${PPM10_H}*256)+${PPM10_L})/10" | bc`
#Update the local InfluxDB
/usr/bin/curl -i -XPOST 'http://127.0.0.1:8086/write?db=smogdb' --data-binary "ppm25sds011 value=${PPM25}"
/usr/bin/curl -i -XPOST 'http://127.0.0.1:8086/write?db=smogdb' --data-binary "ppm10sds011 value=${PPM10}"
else
echo HEADER ERROR
fi
#Turining OFF the USB ports for Orange Pi
/usr/bin/sunxi-pio -m PH26''
Dzięki czytelnikowi bloga – Piotrek Pilek, pozdrowienia, mamy sposób na identyczną kontrolę zasilania USB! (przy okazji – Piotr pracuje w Lantech w Szczecinie – popatrzcie na to niedocenione miasto – https://lantech.com.pl/internet_szczecin_oferta/transmisje-live/)
Kontrolę zasilania USB możemy uzyskać dzięki programowi Vadim Mikhailov, który stworzył oprogramowanie dla kilkunastu róznych hubów USB wraz z obsługą Raspberry Pi. Program instalujemy:
cd ~
sudo apt install libusb-1.0 libusb-dev
git clone https://github.com/mvp/uhubctl
cd uhubctl
make
sudo make install
Następnie modyfikujemy linie w powyższym przykładzie:
/usr/bin/sunxi-pio -m PH26''
na
/usr/sbin/uhubctl -a off -p 2
A następnie analogicznie na końcu pliku:
/usr/bin/sunxi-pio -m PH26''
na
/usr/sbin/uhubctl -a on -p 2
Uwaga – wyłącza to wszystkie porty USB, ale nie wyłącza portu eth0 ani też wlan0
Teraz – podobnie jak wcześniej – rysujemy dane w Grafanie, definicje wyglądają następująco:
SELECT last("value") FROM "ppm25sds011" WHERE $timeFilter GROUP BY time(1m) fill(none)
SELECT last("value") FROM "ppm10sds011" WHERE $timeFilter GROUP BY time(1m) fill(none)
To wszystko!
Nasze dane od smogu są dostępne i bardzo łatwo możemy się nim podzielić. Jeśli prowadzisz własny projekt agregujacy dane – napisz proszę komenatarz lub emaila – dopiszę sposób w jaki można wysłać do konkretnych projektów dane.
Open-Smog to projekt zapoczątkowany jako realizacja pomysłu Artura Kurasińskiego. Po szczegóły zapraszam na Slacka: https://open-smog.slack.com/
Integracja sprowadza się do dodania do skryptu na końcu:
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d "[ { \"data\": { \"pm2_5\": ${PPM25}, \"pm10\": ${PPM10}, \"temp\": ${temperature}, \"hum\": ${humidity} } } ]" 'http://ADRES_WWW_OPENSMOG/v1/Sensors/TWOJEID/data'
Obiecywałem, że będzie prosto, prawda ?
Pomiary, aktualizowane co 60 minut, możecie śledzić pod adresem http://pogoda.jokielowie.com/
Z pewnością każdego interesuje jak dokładny jest taki czujnik. Możemy bardzo szybko dodać do naszego skryptu dane z oficjalnych stacji WIOŚ: mapa znajduje się pod adresem: http://powietrze.gios.gov.pl/pjp/current. Wybieramy interesującą nas stację – w przykładzie będzie to stacja na ul. Koszyka w Opolu, która ma adres: http://powietrze.gios.gov.pl/pjp/current/station_details/chart/10374. Jak zauważył Krzysztof Styc na grupie Domoticz – WIOŚie podają aktualne dane (ostatni pomiar) w formacie JSON. Pod koniec 2017 uległo to jednak zmianie i udostępniono nowe API pod nowym adresem, także w formacie JSON: http://powietrze.gios.gov.pl/pjp/content/api
To pozwala nam szybko wyciągnąć nową zmienną i wpisać ją do bazy InfluxDB – dodając kilka linijek do naszego skryptu. Najpierw musimy jednak znaleźć ID naszej stacji:
http://api.gios.gov.pl/pjp-api/rest/station/findAll
Szukamy np: Opola i znajdujemy StationID:
Mając StationID – wpisujemy je w URL, który pokaże konkretne pomiary:
http://api.gios.gov.pl/pjp-api/rest/station/sensors/10374
A więc mamy nasze ID do pomiarów:
http://api.gios.gov.pl/pjp-api/rest/data/getData/16147
Modyfikujemy skrypt:
city_wios_station=`curl -s http://api.gios.gov.pl/pjp-api/rest/data/getData/16147 | awk -F, '{print $3}' | sed -e 's/}/:/g' | awk -F: '{print $2}'`
if [ $city_wios_station = "null" ] ; then
city_wios_station=`curl -s http://api.gios.gov.pl/pjp-api/rest/data/getData/16147 | awk -F, '{print $5}' | sed -e 's/}/:/g' | awk -F: '{print $2}'`
fi
/usr/bin/curl -i -XPOST 'http://127.0.0.1:8086/write?db=smogdb' --data-binary "ppm10_city_wios_station value=${city_wios_station}"
Oczywiście dla stacji podających więcej danych – należy zmodyfikować nieco kod. Najpierw trzeba znaleźć ID jak powyżej.
Po modyfikacji (przykłady bez optymizacji) możemy pobrać więcej zmiennych, co wymaga jak zwykle małej zabawy z parametrami.
Na wykresie pojawi się więc dodatkowa zmienna – lub zmienne, dzięki której zweryfikujemy nasze wskazania. Dla gazów warto zrobić osobny wykres.
Informację o aktualnych wartościach ilości cząsteczek w metrze sześciennym możemy także prezentować w formie wskaźników lub zegarów. Z pomocą przychodzi gotowa bilblioteka w JavaScript, która współpracuje bezproblemowo z większością przeglądarek: http://justgage.com/:
Pobieramy ZIP „justgauge”, rozpakowujemy i przygotowujemy naszą surową stronę, w przykładzie będziemy jeszcze pobierać dane z bazy InfluxDB – temperaturę i wilgotność, tak abyśmy wiedzieli czy nasz pomiar jest wiarygodny. Surowa wersja strony:
Stacja pogodowa/Weather station
Stacja pogodowa SMOG w ... /SMOG Weather Station in ...
<div id="zegar1"></div>
<div id="zegar2"></div>
<div id="zegar3"></div>
<div id="zegar4"></div>
<script src="raphael-2.1.4.min.js"></script>
<script src="justgage.js"></script>
<script>
var zegar1, zegar2, zegar3, zegar4;
window.onload = function(){
var zegar1 = new JustGage({
id: "zegar1",
value: __ppm25__,
min: 0,
max: 300,
title: "Cząsteczki 2,5µm",
label: "µg/m^3"
});
var zegar2 = new JustGage({
id: "zegar2",
value: __ppm10__,
min: 0,
max: 300,
title: "Cząsteczki 10µm",
label: "µg/m^3"
});
var zegar3 = new JustGage({
id: "zegar3",
value: __temperature__,
min: -40,
max: 60,
title: "Temperatura",
label: "st C"
});
var zegar4 = new JustGage({
id: "zegar4",
value: __humidity__,
min: 0,
max: 100,
title: "Wilgotność",
label: "%"
});
};
</script>
Zapiszmy plik jako raw-index.html
W głównym skrypcie mamy już zmienną która odpowiada na 2,5 i 10. Pobierzmy więc – dodają te line do skryptu – wilgotność i temperaturę. W InfluxDB są to w moim przykładzie zmienne „temperatura_out” oraz „wilgotnosc_out” – zmieniamy je na własne, podobnie jak adres IP i nazwę bazy danych – oczywiście dołączamy do głównego skryptu:
temperature=`/usr/bin/curl -s -G 'http://127.0.0.1:8086/query' --data-urlencode "db=ZMIEN_MNIE" --data-urlencode "q=SELECT last(\"value\") FROM \"temperatura_out\"" | /bin/sed -e 's/[{}]/''/g' | /usr//bin/awk -v k="text" '{n=split($0,a,","); print a[n]}' | tr -d "[\]]"`
humidity=`/usr/bin/curl -s -G 'http://127.0.0.1:8086/query' --data-urlencode "db=ZMIEN_MNIE" --data-urlencode "q=SELECT last(\"value\") FROM \"wilgotnosc_out\"" | /bin/sed -e 's/[{}]/''/g' | /usr//bin/awk -v k="text" '{n=split($0,a,","); print a[n]}' | tr -d "[\]]"`
Gotowe – zatem wymieńmy odpowiednie wartości w naszym pliku i stwórzmy nowy:
sed -e "s/__temperature__/${temperature}/g" -e "s/__humidity__/${humidity}/g" -e "s/__ppm25__/${PPM25}/g" -e "s/__ppm10__/${PPM10}/g" < raw-index.html > index.html
Plik index.html wysyłamy do naszego hostingu na przykład tak, oczywiście wcześniej wykonując „ssh keygen” oraz „ssh-copy-id”
scp index.html [email protected]:/var/www/pogoda.host.com/html/index.html
Każde uruchomienie skryptu zaktualizuje nam plik!