Skocz do zawartości

Przeszukaj forum

Pokazywanie wyników dla tagów 'bme280'.

  • Szukaj wg tagów

    Wpisz tagi, oddzielając przecinkami.
  • Szukaj wg autora

Typ zawartości


Kategorie forum

  • Elektronika i programowanie
    • Elektronika
    • Arduino, ESP
    • Mikrokontrolery
    • Raspberry Pi
    • Inne komputery jednopłytkowe
    • Układy programowalne
    • Programowanie
    • Zasilanie
  • Artykuły, projekty, DIY
    • Artykuły redakcji (blog)
    • Artykuły użytkowników
    • Projekty - roboty
    • Projekty - DIY
    • Projekty - DIY (początkujący)
    • Projekty - w budowie (worklogi)
    • Wiadomości
  • Pozostałe
    • Oprogramowanie CAD
    • Druk 3D
    • Napędy
    • Mechanika
    • Zawody/Konkursy/Wydarzenia
    • Sprzedam/Kupię/Zamienię/Praca
    • Inne
  • Ogólne
    • Ogłoszenia organizacyjne
    • Dyskusje o FORBOT.pl
    • Na luzie
    • Kosz

Szukaj wyników w...

Znajdź wyniki, które zawierają...


Data utworzenia

  • Rozpocznij

    Koniec


Ostatnia aktualizacja

  • Rozpocznij

    Koniec


Filtruj po ilości...

Data dołączenia

  • Rozpocznij

    Koniec


Grupa


Znaleziono 4 wyniki

  1. Cześć! Od paru dni męczę się z odpaleniem czujnika BME/BMP280 - o takiego dokładnie: W międzyczasie przebrnąłem już przez, wydaje mi się, wszystkie czeluści internetu, ale może Wasze doświadczenie jeszcze mi pomoże. Generalnie wszystko starałem się konfigurować i robić analogicznie do tutorialu znajdującego się pod tym linkiem: https://randomnerdtutorials.com/esp32-bme280-arduino-ide-pressure-temperature-humidity/?fbclid=IwAR14vHOzVlIAiPvsUOxV-efDpnfCjG6Ms7q_sTuLk0ypwM-p3ousZU1yn_Y Sprawdzałem poprawność podłączeń, korzystałem z najnowszych bibliotek adafruit, później próbowałem korzystać z tych przedstawionych w tutorialu (zmieniając adres I2C w Adafruit_BME280.h). Zaczynam podejrzewać, że może czujnik jest w jakiś sposób uszkodzony. Może macie jakieś inne sposoby, żeby to sprawdzić? Bo jednak wolałbym się nie nadwrężać dodatkowymi kosztami. Również sugerowałem się filmikiem - niestety komentowanie (w moim przypadku _wire -> begin(); w Adafruit_BME280.cpp i dopisywanie kodu w Arduino IDE również nie pomogło.) Z góry bardzo Wam dziękuję za wszelkie rady Edit. żeby było prościej kod z którego korzystam: /********* Complete project details at http://randomnerdtutorials.com *********/ #include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> /*#include <SPI.h> #define BME_SCK 18 #define BME_MISO 19 #define BME_MOSI 23 #define BME_CS 5*/ #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME280 bme; // I2C //Adafruit_BME280 bme(BME_CS); // hardware SPI //Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI unsigned long delayTime; void setup() { Serial.begin(9600); Serial.println(F("BME280 test")); bool status; // default settings // (you can also pass in a Wire library object like &Wire2) status = bme.begin(0x76); if (!status) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1); } Serial.println("-- Default Test --"); delayTime = 1000; Serial.println(); } void loop() { printValues(); delay(delayTime); } void printValues() { Serial.print("Temperature = "); Serial.print(bme.readTemperature()); Serial.println(" *C"); // Convert temperature to Fahrenheit /*Serial.print("Temperature = "); Serial.print(1.8 * bme.readTemperature() + 32); Serial.println(" *F");*/ Serial.print("Pressure = "); Serial.print(bme.readPressure() / 100.0F); Serial.println(" hPa"); Serial.print("Approx. Altitude = "); Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); Serial.println(" m"); Serial.print("Humidity = "); Serial.print(bme.readHumidity()); Serial.println(" %"); Serial.println(); } I na monitorze dostaje błąd z setupu, "Cold not find a valid BME280 sensor, check wiring!". Przez chwilę myślałem, że to może coś z lokalizacją bibliotek i obiekt "bme" się w ogóle nie tworzy, ale samo IDE biblioteki wyświetla... Edit 2, further information I2C scanner daje mi adres 0x76 - czy w ogóle to, że znajduje jakieś urządzenie nie jest dowodem, że czujnik nie jest zepsuty? czy to leży po stronie ESP32? ESP32, z którego korzystam piny do I2C SDA na D21, i SCL na D22.
  2. Elektroniczny Multitool Jak się zaczęło? Ano zaczęło się od tego, że zanabyłem sobie hulajnogę elektryczną. Długo i sumiennie przeglądałem różne recenzje, opisy, wertowałem informacje, aż w końcu zdecydowałem się na Airwheel Z5 Strong, którą na marginesie polecam. Pomimo wielu zalet - w tym kilku rozwiązań unikalnych w tym segmencie urządzeń, jak na przykład wygodne podesty albo łatwo wymienny akumulator - ma jednak pewną niewielką wadę: brak wyświetlacza informującego na przykład o bieżącej prędkości czy o przejechanej drodze. Ponieważ od jakiegoś czasu bawię się Arduino, stwierdziłem, że stosunkowo łatwo powinno dać się skonstruować taki licznik samodzielnie - wystarczy przecież zastosować GPS, który uniezależnia mnie od rozwiązań zastosowanych w hulajnodze. Zacząłem więc powoli kolekcjonować wszystkie niezbędne komponenty. Wyświetlacz Zacząłem trochę nietypowo, bo od wyświetlacza. Zrobiłem już kilka projektów na wyświetlaczach znakowych, ale - oczywiście - nie dają one takich możliwości, jak solidny, kolorowy, a najlepiej dotykowy wyświetlacz. Mój wybór padł na dotykowy wyświetlacz 2.4", pracujący z rozdzielczością 320x240 i komunikujący się przez popularny protokół SPI. Mój wygląda nieco inaczej niż ten w sklepie, ale różnią się płytką z kontrolerem, wyświetlacz jest ten sam. Kontroler Obejrzałem sobie sporo filmików dotyczących podłączania wyświetlaczy do Arduino i uderzyło mnie to, że w większości przypadków liczba klatek na sekundę osiągała bardzo często wartości jednocyfrowe. Jest to zrozumiałe - wszelkie Uno, Leonardo, Micro i tak dalej są taktowane ze stosunkowo małymi częstotliwościami, a przynajmniej zbyt małymi, by osiągnąć zadowalające rezultaty graficzne. Dlatego tym razem porzuciłem całę rodzinę *ino na rzecz chyba nieco mniej znanego kontrolera, Teensy 3.5. Kosztuje swoje, ale dostajemy naprawdę ciężką artylerię: 120 Mhz, 512 kB Flash, 192 kB RAMu, 62 piny, zintegrowany zegar czasu rzeczywistego (trzeba go tylko zasilić bateryjką CR2032), czytnik kart microSD i oczywiście możliwość programowania przez micro USB, bez konieczności stosowania programatorów. Polecam, korzystanie z takiego kombajnu to naprawdę czysta przyjemność. GPS Ta decyzja była stosunkowo prosta, zdecydowałem się na rozwiązanie ekonomiczne i kupiłem prosty GPS komunikujący się przez UART (szeregowo). Przyznam szczerze, że po zakupie Teensy trochę szkoda było mi poświęcić taki świetny kontroler li tylko na licznik do hulajnogi. Dlatego zanabyłem jeszcze popularny czujnik pogodowy BME280 i stwierdziłem, że w czasie, gdy nie będę korzystał z urządzenia jako licznika, zrobię z niego małą stację pogodową. Na wyposażeniu urządzenia znalazł się również czujnik położenia MPU9250, bo zamierzałem napisać rejestrator pochyłości podłoża (i ewentualnie również jego jakości), ale w końcu z tego pomysłu zrezygnowałem. Być może za jakiś czas dopiszę sobie do urządzenia cyfrową poziomicę. Konstrukcja Zacząłem od płytki prototypowej, która błyskawicznie zamieniła się na totalnie zagmatwaną pajęczą sieć przewodów kydexowych. Myślałem na początku, że poprzestanę na niej, ale plątanina ta wyglądała tak dramatycznie, że z pomysłu w końcu zrezygnowałem, traktując go tylko jako prototyp. Sprawdziłem, czy wszystkie urządzenia będą pracowały prawidłowo i generalnie każdy moduł udało mi się uruchomić i pobrać z niego dane, z tym wyjątkiem, że BME280 i MPU9250 odmawiały współpracy podłączone do jednej szyny I2C. Szczęśliwie Teensy oferuje tych szyn chyba z pięć, więc przepiąłem BME na inną i wszystko wstało bez problemu. Kiedy wszystko działało, siadłem do Eagle'a i zaprojektowałem PCB, który miał zastąpić tę nieszczęsną płytkę prototypową. W Polsce jest kilka firm, które wykonują nawet pojedyncze sztuki takich płytek, a moją zamówiłem w firmie Satland Prototype. Musiałem poczekać dwa tygodnie, ale w końcu płytka doszła pocztą i mogłem zacząć lutować. Jakiś czas temu wyposażyłem się w drukarkę 3D, więc po zlutowaniu (i uruchomieniu) wszystkiego siadłem do Fusion 360 i zaprojektowałem obudowę na całe urządzenie. Zadbałem o to, żeby BME został odseparowany wewnętrzną ścianką od reszty urządzenia, bo ekran LCD potrafi się grzać i zafałszowuje odczyty. GPS zamocowałem w osobnym miejscu, wsunięty w odpowiedni slot i zabezpieczony ścianką z drugiej strony, ponieważ niestety wersja, którą kupiłem, nie posiadała żadnych otworów montażowych. Płytka z komponentami siedzi w przygotowanym na jej wymiary wgłębieniu i jest ściśnięta pomiędzy dwiema częściami obudowy, więc nie ma możliwości się przesunąć. Do tego otwór na wyświetlacz, siateczka w przedniej ściance przepuszczająca powietrze do czujnika pogodowego i tyle. Słowo komentarza, bo pewnie padnie takie pytanie: schemat dotyczy nowej wersji płytki z usuniętym radyjkiem NRF, na zdjęciu jest starsza wersja - szczegóły na końcu artykułu. Programowanie Proces programowania musiałem rozłożyć w czasie, ale projekt szedł powoli do przodu. Zacząłem od części pogodowej, ogrom miejsca w programowalnej pamięci kontrolera pozwolił mi poszaleć, więc przygotowałem sobie w C++ klasy odpowiedzialne za obsługę interfejsu użytkownika, spięcie różnych modułów w jedną całość, wyświetlanie grafiki i tak dalej. Również i tym razem dałem się ponieść - nie mogłem znaleźć w Internecie dobrego programu do generowania czcionek w formacie zrozumiałym dla biblioteki ILI9341_t3 przygotowanej przez twórcę Teensy (działa ona szybciej od regularnej biblioteki), a zależało mi na czcionce siedmiosegmentowej - takiej trochę "retro" (widać na screenach). Zapytałem więc Paula o kilka rzeczy, siadłem któregoś wieczoru i wyrzeźbiłem edytor czcionek dla ILI9341_t3. Mój prosty programik może się podobać lub nie, ale najlepszą alternatywą jaką znalazłem jest gigantyczne makro w Excelu, więc sami rozumiecie... Dużym odkryciem było dla mnie, że na platformę Arduino można już programować w Visual Studio Code - Arduino Studio jest wciąż wymagane (bo zawiera wszystkie narzędzia potrzebne do zbudowania programu dla kontrolerka), ale tak naprawdę wszystkie operacje - budowanie, wrzucanie na płytkę, monitor portu szeregowego - można już obsłużyć bezpośrednio w tym świetnym środowisku. Tylko że... niestety Teensy nie jest całkowicie zgodne z Arduino i do budowania na tę platformę potrzebny jest dodatkowy programik, Teensyduino, który nieco modyfikuje Arduino Studio i nie jest kompatybilny z VS Code. Tym niemniej, większość developmentu zrealizowałem w tym ostatnim, jedynie budując i wrzucając aplikację na urządzenie przy pomocy AS. Zastosowałem też własny mechanizm podwójnego buforowania: cały obraz buduję w RAMie i wyświetlam go hurtem w jednym kroku. Ogranicza to trochę lag związany z wyświetlaniem poszczególnych elementów, opóźnienie wciąż jest, ale jest znacznie mniej zauważalne. Kosztowało mnie to prawie połowę pamięci RAM, ale z uwagi na to, że pozostałe komponenty aplikacji prawie go nie zużywają, mogłem sobie na to pozwolić. Źródła trzymam na Gitlabie, chcecie obejrzeć - sklonujcie sobie repo. Efekt W chwili obecnej płytka w trybie stacji pogodowej wyświetla klasycznie: temperaturę, ciśnienie i wilgotność, a także wykresy: bieżący (jasna linia - jeden piksel to 15 sekund) i historia - 1h, 8h lub 24h wstecz.Tryby można przełączać po dotknięciu ekranu - pojawia się wtedy proste menu. Aplikacja wyposażona jest w wygaszacz ekranu, który zapobiega wypaleniu pikseli - szczególnie, że w trybie stacji pogodowej bardzo dużo z nich mogłoby być na to narażone. Po 30 sekundach ekran się wyłącza (wygasza), a włącza ponownie po dotknięciu. Niestety nie udało mi się wyłączyć jego podświetlenia - doczytałem, że w tym ekranie programowo nie da się tego zrobić. Szkoda. W trybie GPS wyświetlane są na razie podstawowe informacje wczytane z odbiornika: prędkość, wysokość n.p.m., kierunek jazdy, liczba satelit, z których odczytywane są dane oraz położenie geograficzne - długość i szerokość. Za jakiś czas dopiszę pewnie tryb "rowerowy", czyli przebyta droga, średnia i maksymalna prędkość i tak dalej. Aplikację mam napisaną na tyle modularnie, że teraz taki moduł mogę już sobie praktycznie niewielkim kosztem poskładać "z klocków". Problemy Człowiek uczy się na błędach, a mądry człowiek na błędach innych. Podczas rozwijania tego projektu nadziałem się na mnóstwo problemów, więc podzielę się moimi rozwiązaniami - być może komuś oszczędzi to czasu i nerwów. Po pierwsze, zasilanie - w dwóch odsłonach. Pierwsza odsłona - pierwotnie na płytce znajdowało się jeszcze radyjko NRF24, ponieważ jakiś czas temu zbudowałem sobie "satelitę" - małą płytkę z czujnikiem temperatury i wilgotności zasilaną z bateryjki CR2032: miałem nadzieję, że w trybie stacji pogodowej urządzenie będzie również ściągało informacje z tego źródła. Testy bez GPSu wypadły pozytywnie - to widać na zdjęciach - ale po podłączeniu wszystkiego i włączeniu zasilania, ekran rozbłysł na chwilę, a potem powolutku przygasł i zgasł całkowicie. Podejrzewałem od razu NRF, chciałem go rozlutować, ale w trakcie tego procesu oderwałem jeden pad na płytce, więc nie miałem już możliwości łatwego sprawdzenia, czy to on jest winien. Żeby uniknąć dalszych uszkodzeń, podrzuciłem płytkę ojcu, który w pracy ma wysokiej klasy rozlutownicę, a ja zaprojektowałem w międzyczasie drugą, tym razem już bez NRFa. Warto zawsze sprawdzić, czy uda się zasilić wszystkie komponenty - ja leniwie pociągnąłem zasilanie wszystkiego z płytki, a mogłem przecież wstawić na płytkę port microSD i pociągnąć dodatkowe ścieżki bezpośrednio z niego - wtedy obciążyłbym zasilacz (który pewnie nawet by nie sapnął), a nie samą płytkę. Druga kwestia - hulajnoga, którą kupiłem, ma w baterii wyjście USB - można (według instrukcji) doładowywać sobie na przykład komórkę (traktować akumulator jako powerbank). Również do tego portu podłączana jest latareczka, którą można sobie włączyć podczas jazdy. Niestety podczas prób terenowych okazało się, że przysiad napięcia podczas rozpędzania jest tak duży, że płytka gaśnie albo się zawiesza. Musiałem więc zasilić ją z osobnego powerbanku, w przyszłości pomyślę nad zasileniem płytki z osobnego akumulatora albo po prostu baterii. Teraz BME280 - małe ostrzeżenie. Układzik jest rewelacyjny, malutki i stosunkowo dokładny... ale się grzeje! Potrafi rozgrzać się na tyle, że zafałszowuje informacje o temperaturze o 1.5-2 stopnie. Rozwiązanie (proponowane nawet przez Boscha) polega na zmniejszeniu dokładności pomiaru (urządzenie może działać w trybie oversampling, czyli robi np. 8 pomiarów i uśrednia - należy to wyłączyć), wyłączeniu filtrowania (które również poprawia jakość pomiarów), przełączyć się w tryb "forced" - wtedy płytka robi pomiar tylko na życzenie - i ograniczyć pomiary do jednego na minutę (!). Ja nie ograniczyłem się tak bardzo, pomiary mam co 15 sekund, ale mimo wszystko układ się grzeje i na początku na wykresie widać delikatny skok temperatury, który po chwili się stabilizuje. Jest również prawdopodobne, że grzeje się nie tyle BME, co wyświetlacz - podobny problem miałem w innej stacji pogodowej z wyświetlaczem znakowym. Tam temperatura skakała do góry o kilka stopniu po uruchomieniu. Kwestia estetyki - nie zadbałem o to, żeby schować obramowanie ekranu z widocznymi ścieżkami panelu dotykowego. W innych projektach nie popełniam już tego błędu, widoczny jest sam ekran (wygląda to o niebo lepiej). Ogólnie jednak jestem zadowolony, płytka jest rozwojowa, a nowe funkcjonalności mogę dodawać programowo, więc podejrzewam, że wzbogacę ją jeszcze o kilka dodatkowych trybów pracy.
  3. Opis konstrukcji Dość modny ostatnio temat, poruszający jakość powietrza, powstał w celu wykonania pomiarów wpływu kominka w domu na zapylenie. W ten oto sposób powstała stacja pogodowa z prezentacją pomiarów na LCD 2004 z I2C oraz możliwością udostępnienia danych dla Domoticz lub ThingSpeak. Sercem stacji jest układ ESP8266-12F na adapterze ESP Shild. Całość umieszczono na PCB zaprojektowanym w EAGLE. Płytka jest zaprojektowana w sposób umożliwiający szybką wymianę poszczególnych elementów. Może być ona wykorzystywana do programowania ESP z wykorzystaniem złącza PROG (po podpięciu się konwerterem USB-UART), jak również w innych projektach wykorzystujących I2C, wejście analogowe ESP, wejścia cyfrowe. Jako zasilanie wykorzystałem zasilacz 12V 1A, których mam kilkanaście. Dla potrzeb zasilania czujników potrzebujemy zasilania 5V o wydajności prądowej ok 1A. W tym celu wykorzystano przetwornicę impulsową step down - przetwornica DC-DC Mini 360 . Przetwornica, jak i inne elementy jest wymienna (na goldpinach). Takie rozwiązanie wymusiło stosowanie tego samego układu w innych projektach, gdzie miałem dostępne zasilania 24-30VDC). Projekt spodobał się znajomym, więc płytka została od razu wykonana w kilku egzemplarzach na frezarce mojego wykonania. Wygląd PCB od strony druku można zobaczyć na zdjęciach. Realizacja pomiarów: W założeniach miałem mierzyć tylko zawartość pyłów ale w szufladach zalegało jeszcze kilka innych czujników. Stąd też dodatkowe pomiary. Pyły: PM1; PM2,5; PM10 - czujnik PMS5003 Ciśnienie, temperatura, wilgotność - czujnik BME280 Wskaźnik CO2 - czujnik MQ135 Wyniki prezentowane są na LCD oraz przez WiFI korzystając z oprogramowania EasyEsp. Istnieje możliwość konfiguracji oprogramowania w celu przesyłania pomiarów do Domoticz lub ThingSpeak. Oprogramowanie W założeniach miałem napisać własny soft wykorzystując biblioteki dostępne dla Arduino IDE, ale z braku czasu poszedłem na łatwiznę i wykorzystałem EasyEsp. Soft wgrywamy za pomocą oprogramowania Esp8266Flasher - wykorzystujemy połączenie po USB - UART (złącze PROG na PCB). Konfiguracja Proces konfiguracji jest dokonywany z poziomu strony WWW oprogramowania ESPEasy i jest dość intuicyjny. Wszystkie parametry wpisujemy w zakładkach odpowiedzialnych za obsługę sieci, czujników iitp. Oczywiście proces konfiguracji opisany jest dokładnie na stronie projektu ESPEasy. Dla osób nie obeznanych w tej tematyce zamieszczam plik konfiguracyjny mojego projektu wraz z dokumentacją zdjęciową (Konfiguracja ESP). Podsumowanie Na chwilę obecną brak jest obudowy, ale układ powstał jako prototyp i każdy adresat układu ma ją wykonać we własnym zakresie. Sam zrobię to jak skończę inne projekty. Konstrukcja ma sporo wad: 1. Brak kalibracji czujników. 2. Pomiar MQ135 to tylko wskazanie przesunięte o 400 ppm (~poziom CO2 w atmosferze, nie uwzględniam wpływu temperatury i wilgotności). 3. Brak dzielnika napięcia na A0 (ESP ma pomiar 0-1V, MQ135 może dać do 5 V przy 5000 ppm), jednak zakładam, że nie będę miał stężenia ponad 1000ppm w domu. Później przetnę ścieżkę na PCB i dam dzielnik na analogu (co niestety zmniejszy dokładność pomiarów) lub zabezpieczę wejście analogowe diodą zenera. 4. Gotowe oprogramowanie z wieloma wadami, w planach zmiana na własny soft i wysyłanie informacji na Cayenne IOT. Zalety: 1. Prosta modułowa konstrukcja, uniwersalna płytka PCB stosowana przeze mnie w innych projektach. 2. Gotowy soft możliwy do wgrania i konfiguracji dla zupełnych laików. Jeśli ktoś jest zainteresowany dodatkowymi materiałami, to proszę o kontakt PW. W załączniku zamieszczam: 1. EAGLE - schemat w EAGLE 9.1.2 wraz z rysunkiem ścieżek. 2. ESP - oprogramowanie w wykorzystanej wersji. 3. ESP8266Flasher - soft do wgrania oprogramowania. Podczas testów pomiar pyłów miałem na zewnątrz przy mrozach ponad 300 szczytowo i pokrywało się to z lokalną stacją w Połańcu (odchyłka była w granicach 5%). Czujnik PM5003 pracuje u mnie w cyklu 60 sekund pomiary/ 30 minut uśpienie. Żywotność czujnika laserowego to 8000 h. Częstszych pomiarów nie potrzebuję do swoich potrzeb. Czas 60 sekund wystarcza do odpowiedniego wygrzania czujnika i ustabilizowania się pomiarów. Cała stacja pobiera zaraz po starcie ok. 3 W, a po nagrzaniu czujnika MQ135 pobór energii spada do ok. 1,8 W. ESP8266Flasher.zip EAGLE.zip ESP.zip Konfiguracja_ESPEasy.zip
  4. Woltomierz, amperomierz, watomierz, termometr, higrometr, barometr, czujnik zewnętrznej termopary, luksomierz w jednym urządzeniu. Projekt typu "weź wszystko co masz pod ręką, podłącz i zaprogramuj, będzie fajnie!" Dane logować można z terminala portu szeregowego (w tym do pliku - Windows/Linux). Wyniki pomiarów prezentowane są również na stronie WWW, a odczyty odświeżają się na żywo dzięki zastosowaniu technologii AJAX. Część do pomiaru prądu przypomina mój poprzedni projekt multimetru, przy czym wykorzystałem dokładniejszy moduł oparty na INA226 zamiast INA219. Podobnie jak tam zasilacz dla mierzonego obwodu podłączamy z boku do gniazda DC, a odbiornik "karmi się" z gniazd bananowych 4 mm. /* I2C D4 - SCL D3 - SDA */ #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> //#include <Adafruit_INA219.h> #include <INA226.h> //https://github.com/jarzebski/Arduino-INA226 #include <BH1750.h> //https://github.com/claws/BH1750 #include "max6675.h" //https://github.com/adafruit/MAX6675-library #include <LiquidCrystal_I2C.h> char* ssid = "Arduino Multimeter"; //const char *password = ""; //http://github.com/adafruit/MAX6675-library/issues/9#issuecomment-168213845 const int thermoDO = D6; const int thermoCS = D7; const int thermoCLK = D8; ESP8266WebServer server(80); Adafruit_BME280 bme; //Adafruit_INA219 ina219; INA226 ina226; BH1750 lightMeter; MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO); LiquidCrystal_I2C lcd(0x27, 20, 4); unsigned long lastTimeLCD = 0; void setup() { Serial.begin(9600); Wire.begin(D3, D4); Wire.setClock(100000); if (!bme.begin(0x76)) //changed from default I2C adress 0x77 { Serial.println("Nie odnaleziono czujnika BMP085 / BMP180"); while (1) { } } uint32_t currentFrequency; //ina219.begin(); // Default INA226 address is 0x40 ina226.begin(); // Configure INA226 ina226.configure(INA226_AVERAGES_1, INA226_BUS_CONV_TIME_1100US, INA226_SHUNT_CONV_TIME_1100US, INA226_MODE_SHUNT_BUS_CONT); // Calibrate INA226. Rshunt = 0.01 ohm, Max excepted current = 4A ina226.calibrate(0.01 * 1.318, 3); lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE); IPAddress apIP(192, 168, 1, 1); WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); // WiFi.softAP(ssid, password); WiFi.softAP(ssid); server.on("/", handleRoot); server.on("/sensors", handleSensors); server.begin(); lcd.begin(); // lcd.backlight(); } void loop() { server.handleClient(); if (lastTimeLCD == 0 || millis() - lastTimeLCD >= 500) { lastTimeLCD = millis(); lcd.clear(); /* lcd.print(ina219.getBusVoltage_V()); lcd.print("V "); lcd.print(ina219.getCurrent_mA()); lcd.print("mA "); lcd.print(ina219.getPower_mW()); lcd.print("mW"); lcd.setCursor(0, 1); */ float volt = ina226.readBusVoltage(); float amp = 1000.0 * ina226.readShuntCurrent(); float power = 1000.0 * ina226.readBusPower(); int lux = lightMeter.readLightLevel(); float tempThero = thermocouple.readCelsius(); float temp = bme.readTemperature(); float hum = bme.readHumidity(); float pres = bme.readPressure(); lcd.print(volt); lcd.print("V "); lcd.print(amp, 1); lcd.print("mA "); lcd.setCursor(0, 1); lcd.print(power, 0); lcd.print("mW "); lcd.print(lux); lcd.print(" lx "); lcd.print(tempThero); lcd.print("C"); lcd.setCursor(0, 2); lcd.print(temp, 1); lcd.print("C "); lcd.print(hum, 1); lcd.print("% "); lcd.print(pres, 0); lcd.print("Pa"); Serial.println(String(volt) + "V " + String(amp, 1) + "mA " + String(power, 0) + "mW " + String(lux) + " lx " + String(tempThero) + "C " + String(temp, 1) + "C " + String(hum, 1) + "% " + String(pres, 0) + "Pa"); } } void handleRoot() { String content = "<html> <head><title>Ardunio Multimeter</title></head><body>"; content += "<DIV style=\"display:table; font-size: large;\"><DIV style=\"border-style: solid;\">BME280:<BR>Temperature: <span id=\"tempBME\"></span>C / <span id=\"tempBMEF\"></span>F<br>Humidity: <span id=\"humBME\"></span>%<br>Pressure: <span id=\"presBME\"></span>Pa<br></DIV><DIV style=\"border-style: solid;\">INA219:<BR>Voltage: <span id=\"voltage\"></span>V<br>Current: <span id=\"current\"></span>mA<br>Power: <span id=\"power\"></span>mW<br></DIV> <DIV style=\"border-style: solid;\">BH1750:<BR>Illuminance: <span id=\"illuminance\"></span>lx</DIV> <DIV style=\"border-style: solid;\">MAX6675:<BR>Temperature: <span id=\"thermocouple\"></span>C / <span id=\"thermocoupleF\"></span>F</DIV></DIV>"; content += "<script>myTimer();var myVar = setInterval(myTimer, 1000);function myTimer() {var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var str = this.responseText; var values = str.split(\";\"); document.getElementById(\"tempBME\").innerHTML = values[0]; document.getElementById(\"tempBMEF\").innerHTML = (values[0]*9/5 + 32).toFixed(2); document.getElementById(\"humBME\").innerHTML = values[1]; document.getElementById(\"presBME\").innerHTML = values[2]; document.getElementById(\"voltage\").innerHTML = values[3]; document.getElementById(\"current\").innerHTML = values[4]; document.getElementById(\"power\").innerHTML = values[5]; document.getElementById(\"illuminance\").innerHTML = values[6]; document.getElementById(\"thermocouple\").innerHTML = values[7]; document.getElementById(\"thermocoupleF\").innerHTML = (values[7]*9/5 + 32).toFixed(2);} }; xhttp.open(\"GET\", \"sensors\", true); xhttp.send();}</script>"; content += "</body></html>"; server.send(200, "text/html", content); } void handleSensors() { //String content = String(bme.readTemperature()) + ";" + String(bme.readHumidity()) + ";" + String(bme.readPressure()) + ";" + String(ina219.getBusVoltage_V()) + ";" + String(ina219.getCurrent_mA()) + ";" + String(ina219.getPower_mW()) + ";" + String(lightMeter.readLightLevel()) + ";" + String(thermocouple.readCelsius()) + ";"; String content = String(bme.readTemperature()) + ";" + String(bme.readHumidity()) + ";" + String(bme.readPressure()) + ";" + String(ina226.readBusVoltage()) + ";" + String(1000.0 * ina226.readShuntCurrent()) + ";" + String(1000.0 * ina226.readBusPower()) + ";" + String(lightMeter.readLightLevel()) + ";" + String(thermocouple.readCelsius()) + ";"; server.send(200, "text/plain", content); } Z zestawem łączy się prymitywna aplikacja napisana w C++. Potrafi zapisywać pomiary do pliku tekstowego i baz danych MySQL oraz SQLite. Jej pracę kończymy w bardzo "brutalny" sposób: Ctrl + C (podobnie, jak w loggerze dla poprzedniego multimetru). Przy pisaniu skorzystałem z poradnika (uwaga, strona zawiera dziwne, procesorożerne skrypty, które mogą nawet zawiesić przeglądarkę, radzę zatrzymać jej ładowanie [przycisk "X"] tuż po otwarciu) Server and client example with C sockets on Linux. Kompilacja: g++ webclient2mysql.cpp -L/usr/lib/mysql -lmysqlclient -l sqlite3 -o webclient2mysql -std=c++17 Jako parametry wywoływanego programu podajemy adres strony www urządzenia z wartościami pomiarów oraz interwał czasu (w sekundach), z jakim mają być zapisywane pomiary, np: ./webclient2mysql http://192.168.1.1/sensors 5 //g++ webclient2mysql.cpp -L/usr/lib/mysql -lmysqlclient -l sqlite3 -o webclient2mysql -std=c++17 //www.binarytides.com/server-client-example-c-sockets-linux/ /* #define DB_USER "" #define DB_PASSWORD "" #define DB_HOST "" #define DB_PORT 3307 #define DB_NAME "" */ #define DB_TABLE_NAME "logeddata" #define DB_SQLite_FILE "database.db" #define LOG_FILE "log.txt" #define CSV_DELIMITER ';' #define CSV_DELIMITER_COUNT 8 //Quantity of delimiters in one CSV row. #include <stdio.h> //printf #include <string.h> //strlen #include <sys/socket.h> //socket #include <arpa/inet.h> //inet_addr #include <unistd.h> #include <netdb.h> #include <iostream> #include <string> #include <vector> #include <chrono> #include <ctime> #include <thread> // std::this_thread::sleep_for #include <regex> #ifdef DB_HOST #include <mysql/mysql.h> //libmysqlclient-dev #endif #ifdef DB_SQLite_FILE #include <sqlite3.h> //sudo apt-get install sqlite3 libsqlite3-dev #endif #ifdef LOG_FILE #include <fstream> #endif const std::vector<std::string> explode(const std::string& s, const char& c); const std::string variables[][2] = { {"temperature", "float"}, {"humidity", "float"}, {"pressure", "float"}, {"voltage", "float"}, {"current", "float"}, {"power", "float"}, {"luminosity", "float"}, {"temperaturethermocouple", "float"}}; int main(int argc, char *argv[]) { if (argc != 3) { puts("Usage: ./webclient device_webpage_URL time_interval"); return 0; } const std::string s = argv[1]; std::smatch match; std::regex rgx("\/\/(.+?)\/"); std::string hostname, port; if (std::regex_search(s.begin(), s.end(), match, rgx)) { hostname = std::string(match[1]); if (hostname.find(":") != std::string::npos) { port = hostname.substr(hostname.find(":") + 1); hostname = hostname.substr(0, hostname.find(":")); } else { port = "80"; } } rgx = "\/\/.+?(\/.+)"; std::string path; if (std::regex_search(s.begin(), s.end(), match, rgx)) path = std::string(match[1]); std::cout << hostname << " " << port << " " << path << "\n"; int sock; struct sockaddr_in server; char server_reply[2000]; #ifdef DB_HOST MYSQL mysql; mysql_init(&mysql); if(mysql_real_connect(&mysql, DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, DB_PORT, NULL, 0)) printf("Connected to database!\n"); else printf("Can't connect to database: %d, %s\n", mysql_errno(&mysql), mysql_error(&mysql)); #endif #ifdef DB_SQLite_FILE char * error = 0; int rc; sqlite3 * db; sqlite3_stmt * steatment; sqlite3_open(DB_SQLite_FILE, & db); #endif #ifdef LOG_FILE std::ofstream myfile; myfile.open(LOG_FILE, std::ios::out | std::ios::app); #endif std::string query; #ifdef DB_HOST query = "CREATE TABLE IF NOT EXISTS " + std::string(DB_TABLE_NAME) +" (ID int NOT NULL AUTO_INCREMENT,"; for(int i = 0; i < sizeof(variables) / sizeof(variables[0]); i++) { query += variables[i][0] + " " + variables[i][1] + ","; } query += "date_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (ID))"; std::cout << query << std::endl; mysql_query(&mysql, query.c_str()); #endif #ifdef DB_SQLite_FILE query = "CREATE TABLE IF NOT EXISTS " + std::string(DB_TABLE_NAME) +"(ID integer primary key,"; for(int i = 0; i < sizeof(variables) / sizeof(variables[0]); i++) { query += variables[i][0] + " " + variables[i][1] + ","; } query += "date_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP)"; sqlite3_exec(db, query.c_str(), 0, 0, & error); // std::cout << error; #endif query = ""; while (1) { //Create socket sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { printf("Could not create socket"); } puts("Socket created"); server.sin_addr.s_addr = inet_addr(hostname.c_str()); server.sin_family = AF_INET; server.sin_port = htons(stoi(port)); //Connect to remote server if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) { perror("connect failed. Error"); return 1; } puts("Connected\n"); std::string message = "GET " + path + " HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"; puts(message.c_str()); //Send some data if (send(sock, message.c_str(), strlen(message.c_str()), 0) < 0) { puts("Send failed"); return 1; } std::string httpContent = ""; char cur; while ( read(sock, &cur, 1) > 0 ) { //Receive a reply from the server httpContent += cur; } httpContent = httpContent.substr(httpContent.find("\r\n\r\n") + 4); std::time_t currentTime = std::time(nullptr); std::vector<std::string> results; results = explode(httpContent, CSV_DELIMITER); std::cout << results.size() << "\n"; if(results.size() == CSV_DELIMITER_COUNT){ std::cout << currentTime << " " << httpContent << "\n"; #ifdef LOG_FILE myfile << currentTime << " "; for (int i = 0; i < sizeof(variables) / sizeof(variables[0]); i++){ myfile << " " << results[i]; } myfile << " " << std::endl; #endif query = "INSERT INTO " + std::string(DB_TABLE_NAME) + " ("; for (int i = 0; i < sizeof(variables) / sizeof(variables[0]); i++){ query += variables[i][0]; if(i < sizeof(variables) / sizeof(variables[0]) - 1) {query += ",";} } query += ") VALUES ("; for (int i = 0; i < sizeof(variables) / sizeof(variables[0]); i++){ query += "'" + results[i] + "'"; if(i < sizeof(variables) / sizeof(variables[0]) - 1) {query += ",";} } query += ")"; // query = "INSERT INTO " + std::string(DB_TABLE_NAME) + " (temperature, humidity, pressure" + ") VALUES ("+ "'" + std::string(results[0]) +"'," + "'" + std::string(results[1]) +"',"+ "'" + std::string(results[2]) +"'" +")"; #ifdef DB_HOST mysql_query(&mysql, query.c_str()); #endif #ifdef DB_SQLite_FILE sqlite3_exec(db, query.c_str(), 0, 0, & error); //std::cout << error; #endif } close(sock); std::this_thread::sleep_for(std::chrono::seconds(atoi(argv[2]))); } #ifdef LOG_FILE myfile.close(); #endif #ifdef DB_HOST mysql_close(&mysql); #endif #ifdef DB_SQLite_FILE sqlite3_close( db ); #endif return 0; } const std::vector<std::string> explode(const std::string& s, const char& c) //http://www.cplusplus.com/articles/2wA0RXSz/ { std::string buff{""}; std::vector<std::string> v; for(auto n:s) { if(n != c) buff+=n; else if(n == c && buff != "") { v.push_back(buff); buff = ""; } } if(buff != "") v.push_back(buff); return v; } Podgląd bazy SQLite z wynikami pomiarów (SQLite Browser) Składniki: ESP8266 wyświetlacz LCD 4x20 z konwerterem I2C LCM1602 moduł miernika napięcia i natężenia prądu z magistralą I²C INA226 BME280 czujnik termopary MAX6675 czujnik natężenia światła BH1750 bezpiecznik (zastosowałem PPTC 3A) gniazdo oraz wtyki bananowe 4 mm gniazdo DC 5.5/2.1 mm
×
×
  • Utwórz nowe...