logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

HomeIO - sterownik kontrolowany komendami MQTT

XS_Sowa 12 Lut 2024 22:44 1695 5
  • HomeIO - sterownik kontrolowany komendami MQTT

    Cześć.

    Od jakiegoś czasu chodził mi po głowie projekt dzięki któremu mógł bym sobie sterować światła w domu i w ogrodzie poprzez wifi. Funkcjonalność banalnie prosta i spotykana w zapewne tysiącach rożnych projektów, jeszcze jeden nie zaszkodzi. :) W trakcie rozmyślania i projektowania kilka razy naszły mnie ciekawe myśli odnośnie naszego hobby, postaram się je także tutaj wtrącić.

    Pierwsza, prototypowa, wersja projektu powstała 1.5 temu. Okazało się, że moje założenia nie były do końca dobre. Design kiepski, zasilacz, ze względu na wybrane przetwornice, przy większym obciążeniu grzał się dość znacznie, kilka małych baboli na schemacie- no ale, to prototyp. Na to wszystko, podczas pisania programu niechcący płytę z CPU włożyłem odwrotnie co poskutkowało spalonym STM32. Mądry ja, zamawiając części kupiłem tylko jedną sztukę mikrokontrolera, tak więc ogólnie zniechęcony, projekt odstawiłem i zająłem się innym, mając w głowie też to, że muszę się podszkolić trochę w kwestii programowania (i designu ;) ).

    Minęło trochę czasu, pracując w dziale quality controll ciągle miałem z tyłu głowy to, że chciał bym zmienić pracę w której będę mógł bardziej zająć się projektowaniem oraz programowaniem elektroniki. Wiedząc, że badania i rozwój (personalny) kosztują, przy projektowaniu i zamawianiu części nie zważałem na to czy jest jakikolwiek sens ekonomiczny takiego projektu. Zapewne nie ma, całość na upartego zapewne można było by poskładać na chińskich modułach i raspbery pi, łącząc wszystko kabekami i wrzucając do większej obudowy. Widząc poradniki tego typu, wraz z rysunkami gdzie schemat elektroniczny jest zastąpiony kablami narysowanymi w paincie które łączą gotowe moduły, czuję niesmak ;-)

    Tak czy inaczej, założenia projektu:
    -Obudowa na szynę DIN tak aby całość mieściła się w rozdzielni elektrycznej
    -Kontrola za pomocą telefonu oraz fizycznymi przyciskami
    -3 wyjścia przekaźnikowe
    -3 wejścia cyfrowe
    -3 wejścia analogowe
    -4 wyjścia PWM z możliwością wyboru poziomu napięć wyjściowych
    -Możliwość sterowania diodami RGB WS28XX
    -Izolacja galwaniczna CPU od wejść/wyjść sterownika, tak jak jest to realizowane w sterownikach PLC
    -Możliwość rozbudowy o kolejne moduły

    =====
    Obudowa
    =====

    W zasadzie od tego zacząłem aby wiedzieć ile miejsca na PCB posiadam. W swojej rozdzielni mam wolny jeden rząd, w sumie 12 modułów. Zasilacz 12V/4.5A zajmuje 3 moduły. Zasilacz 24V który być może także będzie zamontowany zajmie 2 moduły.
    Tak więc dodając bezpiecznik, wychodzi nam obudowa 6 modułowa. Wybór padł na obudowę dostępną na TME, D6MG. Nie jest droga, jakościowo myślę, że lepsza niż te dostępne na aliexpress. Obudowa nadaje się do złącz śrubowych o rastrze 5.08mm, 16 przyłączy z każdej strony.

    W ogrodzie jest osobna instalacja świetlna która zbiega się do jednego punktu, tam rozdzielnia na 10 pól będzie wystarczająca. Pomiędzy rozdzielnią w domu a w ogrodzie poprowadzone jest zasilanie oraz RJ45. Obudowa na chwilę obecną nie ma żadnego nadruku, chcę to zrobić sitodrukiem aby było ładnie i estetycznie; obecnie jestem na etapie szukania drukarni w okolicy która mi to zrobi.

    =====
    Kontrola za pomocą telefonu
    =====

    W tej kwestii zaszła chyba największa zmiana w stosunku do pierwszej wizji projektu. Pierwotnie chciałem stworzyć coś na wzór własnego API, poleceniami POST lub GET. Logowanie historii (z tego akurat została pamięć flash na płycie :) )oraz ewentualne skrypty miały by być zapisywane i wykonywane przez CPU. Sama komunikacja miała odbywać się poprzez wifi. Finalnie doszedłem do wniosku, że jest to trochę przesadą, było by nie praktyczne, czasochłonne, niczym wymyślenie koła na nowo. Szukając możliwości zdecydowałem się na użycie protokołu MQTT, najpopularniejszego obecnie rozwiązania stosowanego w IoT. Nie miałem z nim wcześniej styczności, podobnie jak z Home Assistant na który natrafiłem w trakcie poszukiwań. Po researchu okazało się, że taka kombinacja może spisać się dość dobrze, CPU będzie musiało "tylko" zająć się odpowiednim wysterowaniem wyjść oraz obsługą sieci, Home Assistant przejmie na siebie logowanie oraz skrypty (które mogą być także pisane w pythonie). Dla pełnej stabilności zdecydowałem się zrezygnować z wifi na rzecz LAN.

    =====
    Hardware
    =====
    1. Zasilacz:
    Projekt podzieliłem na 2 płytki, dolna to zasilacz, górna to CPU. W obudowie jest wystarczająco miejsca aby włożyć 3 płytę pomiędzy, jednak w tym przypadku nie ma takiej potrzeby. Zasilacz przewidziany jest na 12V, ze względu na zewnętrzne oświetlenie które posiadam, jednak nic nie stoi na przeszkodzie aby używać także 24V. W takim przypadku pamiętać należy o zmianie diód TVS oraz kondensatorów na elementy o odpowiednio wyższym napięciu. Główne przetwornice tolerują napięcie do 40V, więc zakres zasilania jest dość spory. Na schemacie (strona 4) widzimy filtrację EMI oraz zabezpieczenie zasilania. Przewidziany bezpiecznik to 5A. Układ idealnej diody składa się z mosfetu SI7850DP oraz sterownika LM74610, jest to zabezpieczenie przed odwrotnym podpięciem zasilania. W momencie kreślenia, wydaje mi się, że układ U20 był dostępny na LCSC, gdy zamawiałem, już nie. Płytka była już zrobiona i nie mogłem znaleźć żadnego odpowiednika dla tego układu u naszych chińskich przyjaciół więc na moim zasilaczu nie jest zamontowany a dren i źródło tranzystora U20 są zwarte ze sobą (aka. życie na krawędzi ;) ).

    Swoją drogą, cały prototyp, jak i wszystkie poprzednie swoje projekty, składałem na częściach z mousera. Finalną wersję projektu złożyłem na układach dostępnych na LCSC (poza mikrokontrolerem). Nie ukrywam, że jestem ciekawy jak sprawdzą się w długim okresie czasu. Muszę przyznać, że ceny są o wiele niższe niż na zachodnich hurtowniach i przy następnych projektach będę chyba używał właśnie elementów z tego miejsca (pyzatym JLCPCB i tak korzysta z ich stanu magazynowego)

    Analizując schemat, zacznę od środka :) W zasilaczu, zastosowane główne przetwornice to GBI1450SMAR. Napięcie wejściowe to 4-40V, maksymalny prąd wyjściowy to 5A, skuteczność na poziomie 90% przy napięciu zasilania 12V. Przetwornica posiada w sobie zintegrowane mosfety kluczujące o rezystancji przewodzenia 80mOhm, ilość zewnętrznych elementów jest jest bardzo mała, więc stopień skomplikowania jest znikomy. Przy testach, podczas włączonych 100 ledach RGB przez godzinę, pobór prądu na lini 5V wynosił 3A. Układ był ciepły, spokojnie można było trzymać na nim palec. Samo PCB jest zaprojektowane tak aby pad termiczny do którego układ jest przylutowany miał kontakt z dużą ilością miedzi, na górnej i dolnej warstwie płytki, nie ma więc potrzeby stosowania dodatkowego radiatora. Przetwornica generuje napięcie dla diód RGB.

    Na schemacie można zobaczyć drugi, identyczny układ który także generuje 5V. Jest to napięcie które nie wychodzi "na zewnątrz" płytki i służy do zasilania płytki z CPU. Napięcie nie jest jeszcze izolowane, założeniem jest tutaj takie aby ewentualne zwarcie na którejkolwiek linii zasilania/io nie zakłóci to komunikacji ze sterownikiem.


    Dodatkowo dla przetwornika ADC zastosowałem osobny stabilizator liniowy CJ6376 (wejście 2.5V-36V) którego napięcie napięcie wyjściowe to także 5V (300mA).


    Na stronie 5 widać filtrację oraz zabezpieczenie wejść analogowych. Napięcie mierzone na dzielniku napięcia zrobionym z rezystorów R13/16/18 oraz rezystancją która jest wpięta w złącza śrubowe.

    Strona 6 to kontrola PWM. Izolacja galwaniczna wykonana jest na izolatorach logicznych 120U31. Napięcie +5V_ISO jest dostarczane z płytki CPU. układy TF0211C to kontrolery bramek które sterują mosfetami SI7850DP. Zworkami U32-U34 możemy wybrać czy napięcie PWM to napięcie zasilania czy V_EXT, które możemy wpiąć z zewnątrz. Opcja ta jest przydatna w przypadku jeżeli będe chciał sterować urządzeniami na 24V.

    Na stronie 7 widać złącza dla płytki z CPU. Wszystkie ścieżki zaznaczone na czerwono znajdują się "na" izolowanej masie GND_ISO. Dodatkowo na tej stronie widać diody zabezpieczające przed ESD dla magistrali CAN.

    Na pierwszych stronach schematu widać przekaźniki oraz wejścia cyfrowe które są izolowane za pomocą transoptorów. Przekaźniki to Omron G5NB-1A-E-DC5, więc nie taka chińszczyzna ;) Maksymalny prąd styków to 5A przy 230VAC/30VDC.

    =====
    CPU
    =====

    Na wstępie chciał bym podziękować koledze szczywronek za jego poradnik STM32 na rejestrach. Dzięki niemu w sumie na dobre ruszyłem z 32 bitowymi CPU. Nie pamiętam kiedy pierwszy raz przeczytałem jego książkę, ale teraz widzę, że temat jest z 2015 roku.. oO


    Tak czy inaczej, zastosowany mikrokontroler to STM32L433CCU6. Zasilacz to izolowana przetwornica 5V/5V o prądzie wyjściowym 400mA. 3.3V generowane jest przez stabilizator liniowy 1117 3.3V. Do mikrokontrolera dołączona jest pamięć flash W25Q128 poprzez interfejs QSPI. Pierwotnie chciałem tam umieścić historię pomiarów, jednak home assistant robi to za mnie :) W przyszłości może wykorzystam ją jako pamięć bootloadera lub jako "przechowalnia" na update firmwareu, na chwilę obecna jest nie używana. Procesor debugowany jest poprzez SWD dostępny na złączu U10. Układ U14 to optoizolator logiczny 122A32 dla szyny danych diód RGB.

    Karta sieciowa to ENC28J60. W zasadzie jego aplikacja to kopiuj-wklej z noty katalogowej. Złącze internetowe RVB-Z-0004 posiada w sobie transformatory sieciowe.

    Układ ADC to MCP3008 - 10 bitowy przetwornik. Mikroprocesor posiada w sobie oczywiście także przetwornik ADC, jednak ze względu na izolacje galwaniczną, łatwiej jest zaizolować cyfrowe SPI (poprzez układy U12-U13) niż analogowe wejścia.

    Układ ISO1050DUBR to izolowany transrecivier szyny CAN. Szyna służy do komunikacji z innymi modułami które mogą być dopięte przez złącza śrubowe. Do CAN jeszcze nie doszedłem, jednak w opisie software pokaże, jak rozwiązałem opcję modularności. Generalnie, mając złącze internetowe nie ogranicza nas nic :)

    Diody led sterowane są poprzez rejestr przesuwny 74HC595. Ledów jest 8, jedna oznacza status połączenia z brokerem (jeżeli miga- trwa łączenie), inne to status wyjść PWM oraz przekaźnikowych. Diody PWM migają z częstotliwością 1Hz jeżeli PWM ma wartość 1-99%.

    Na zdjęciach widać też modyfikacje które należy zrobić, w ostatnim momencie tworzenia schematu zdecydowałem się na inny CPU, przy zmianie symbolu gdzieś mi się zapodziała masa na pinie boot.
    ====
    Software
    ====

    Pierwotnie pisząc na płytce Nucleo myślałem o użyciu MBED, którego generalnie nie lubiłem/nie lubię i zdecydowanie kładę go na półce obok arduino. Generalnie zawsze sobie wszystko pisałem w STM32CUBE przy użyciu CMSIS.

    Tak czy inaczej, chciałem użyć mbed, głównie ze względu na prostotę inicjacji ENC oraz MQTT (oraz hasła reklamowe typu " Mbed makes device development quicker". Dobre...) . O ile na nucleo byłem w stanie uruchomić sieć i zainicjować połączenie z brokerem, o tyle w moim projekcie użyłem trochę innego CPU niż jest na nucleo. Okazuje się, że przeportowanie projektu to nie taka prosta sprawa, a o support, jeżeli coś wykracza poza nucleo/arduino/moduły na kabelkach też jest ciężko. Stwierdziłem więc, że troche się pomęcze i spróbuje wszystko zrobić STM32Cube. Podłączenie LwIP oraz sterowników do ENC okazały się nie takie straszne, stąd już droga krótka :)

    Generalnie płytka próbuje się połączyć z brokerem pod adresem 192.168.1.2. Po udanym połączeniu subskrybuje tematy COMMAND oraz SETTING. Dostępne komendy:

    DOUTx= ON/OFF/TOGGLE
    PWMx=ON/OFF/0-100
    RGB_BRIGHTNESS=0-100
    RGB=a,r,g,b

    Płytka wysyła do brokera na bieżąco (przy każdej zmianie) informacje do tematu OUTPUT- Wartości RAW adc oraz status wyjść. Sprzętowe wejścia cyfrowe są softwareowo "spięte" z wyjściami. Każda zmiana stanu wejścia 1 powoduje "toggle" wyjścia 1, tak więc możemy sobie sterować wyjściem i sprzętowo i MQTT. Być może takie powiązanie zrobię w formie skryptu w home assistant, zobaczę w praktyce :)
    Przy komendzie RGB możemy zaadresować konkretną diodę (a=0-100) lub ustawić cały łańcuch w takim samym kolorze (a=255). Ze względu na ograniczenia prądowe, płyta adresuje 100 diód. Przy 100 didodach odpalonych na 100% prąd to równe 3A.

    W temacie SETTING możemy zmieniać ustawienia:


    if (strstr (payload, "IP="))
    if (strstr (payload, "GATEWAY="))
    if (strstr (payload, "NETMASK="))
    if (strstr (payload, "SERVER="))
    if (strstr (payload, "PWM_PSC="))
    if (strstr (payload, "DIMMING="))
    if (strstr (payload, "NAME="))
    if (strstr (payload, "SAVE"))
    if (strstr (payload, "RESET"))
    if (strstr (payload, "SHOW"))

    PWM_PSC to preskaler PWM w przypadku gdybym chciał zmienić częstotliwość.
    DIMMING to czas w milisekundach jaki potrzebny jest do rozjaśnienia PWM od 0 do 100 (dla płynnego załączanie LEDów)
    NAME to nazwa płytki. Jest to nazwa tematu do którego wysyłane będą wszystkie informacje. Ze względu na to, że każdy sterownik może mieć swoją nazwę, nie mam takiego ciśnienia na uruchomienie CAN, wszystko może być adresowane po LANie.
    SAVE zapisuje nowe informacje do pamięci flash mikrokontrolera
    RESET resetuje płytkę
    SHOW pokazuje obecne ustawienia w temacie SETTINGS (w tym adres MAC to 02:32:xx:xx:xx gdzie xx to uniqueid CPU)

    ====
    Podsumowanie
    ====

    Ogólnie podczas tworzenia tego i poprzedniego projektu kilka razy miałem poważny kryzys i chciałem całą elektronikę którą zajmuje się w wolnej chwili rzucić w cholerę, tymbardziej ciesze się, że w końcu mogę go opublikować :) Nauczyłem się przy nim całej masy nowych rzeczy, dzięki nim, udało znaleźć mi się pracę w której zawodo mogę zajmować się także projektowaniem PCB i pisaniem w pythonie, więc warto dążyć do celów które się sobie postawiło :)

    Poniżej krótki film z działania i kilka zdjęć :)

    HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT HomeIO - sterownik kontrolowany komendami MQTT
    Film: https://www.youtube.com/shorts/d-oAgr_vQ2Y

    Źródła oraz pliki projektów z EasyEDA (folder _Hardware) dostępne są na githubie:

    https://github.com/perpuchaty/HomeIO

    Pozdrawiam, Kamil.

    Fajne? Ranking DIY
    O autorze
    XS_Sowa
    Poziom 13  
    Offline 
    Specjalizuje się w: elektronika - projektowanie, embedded, serwis laptopy
    XS_Sowa napisał 93 postów o ocenie 97, pomógł 6 razy. Mieszka w mieście Rotterdam. Jest z nami od 2014 roku.
  • #2 20959044
    Arkazar
    Poziom 10  
    Przymierzam się do podłączenia swoich modułów pod sieć także w wolnej chwili spojrzę na to z chęcią. To działa bez rasberry pi? Dostęp masz tylko z domowej sieci czy spoza też na home assistant? Pewnie spotkałeś się z czymś takim na ESP 32, jakie plusy ma to rozwiązanie?[/td]
  • #3 20959747
    gulson
    Administrator Systemowy
    Bardzo dziękuję za podzielenie się rozwiązaniem! Jak mi wyślesz nr Paczkomatu lub adres, to wyślę mały upominek, także poza Polską! :)
  • #4 20965119
    XS_Sowa
    Poziom 13  
    Arkazar napisał:
    Przymierzam się do podłączenia swoich modułów pod sieć także w wolnej chwili spojrzę na to z chęcią. To działa bez rasberry pi? Dostęp masz tylko z domowej sieci czy spoza też na home assistant? Pewnie spotkałeś się z czymś takim na ESP 32, jakie plusy ma to rozwiązanie?[/td]
    Tak, to działa bez rasberry pi. Jeżel home assistant jest wystawiony na zewnątrz, to dostęp do urządzenia jest nieograniczony.

    Przykładowa implementacja ADC w home assistant:
    Cytat:

    sensor:
    - name: "STM32_ADC1"
    state_topic: "STM32/OUTPUT/ADC1/"
    unit_of_measurement: mV
    payload_available: "online"
    payload_not_available: "offline"
    - name: "STM32 ADC2"
    state_topic: "STM32/OUTPUT/ADC2/"
    unit_of_measurement: mV
    payload_available: "online"
    payload_not_available: "offline"


    Konwersja wartości RAW do rezystancji oraz temperatury:
    Cytat:
    sensor:
    - platform: template
    sensors:
    stm32_temperature_1:
    friendly_name: "STM32 Temperature"
    unit_of_measurement: "°C"
    value_template: "{{ states('sensor.stm32_temp_ch1') }}"
    stm32_resistance_1:
    friendly_name: "STM32 Resistance CH1"
    unit_of_measurement: "°C"
    value_template: "{{ states('sensor.stm32_resistance_ch1') }}"


    Skrypt python wykonywany przy każdej aktualizacji wartości ADC który przelicza wartość RAW do temperatury (dla NTC10k):
    Cytat:
    # File: config/python_scripts/convert_ntc_to_temperature.py

    def custom_log(x):
    if x <= 0:
    raise ValueError("Logarithm undefined for non-positive values")
    return 0.693147 * ((x - 1) + 0.5 * (x - 1)**2)
    temperature_sensor = "sensor.stm32_temperature_1"
    resistance_entity = "sensor.stm32_resistance_1"

    # Specify B25/50 value from your thermistor's datasheet
    B25_50 = 3950.0 # Replace with your actual B25/50 value

    # Reference values
    R0 = 10000.0
    T0 = 25.0 + 273.15 # Convert reference temperature to Kelvin

    # Get NTC resistance from sensor state
    ntc_state = hass.states.get("sensor.STM32_ADC1")
    # Check if the state is a valid number
    if ntc_state and ntc_state.state.replace('.', '', 1).isdigit():
    ntc_resistance = float(ntc_state.state)
    ntc_resistance=(ntc_resistance*10000)/(1024-ntc_resistance)
    ntc_resistance=round(ntc_resistance,2)

    # # Calculate temperature from NTC resistance without using import math
    # temperature_kelvin = 1 / (A + B * (ntc_resistance ** -1) + C * ((ntc_resistance ** -1) ** 3))
    # temperature_celsius = temperature_kelvin - 273.15
    temperature = 20
    R0 = 10000
    #ntc_resistance=1000
    temperature_kelvin = 1 / ((1 / T0) + (1 / B25_50) * custom_log(ntc_resistance / R0))
    temperature_celsius = temperature_kelvin - 273.15
    # Update temperature sensor
    hass.states.set(resistance_entity, ntc_resistance)

    hass.states.set(temperature_sensor, temperature_celsius, {
    "unit_of_measurement": "°C",
    "friendly_name": "STM32 Temperature"
    })

    else:
    # Handle the case when the state is not a valid number
    logger.warning("Invalid NTC state: %s", ntc_state.state)


    ESP32 napewno jest bardziej elastyczny i daje większe możliwości. Chciałem pokazać jak może wyglądać implementacja własnych odczytów w home assistant używając własnego CPU, innego niż ESP.

    Cytat:
    Bardzo dziękuję za podzielenie się rozwiązaniem! Jak mi wyślesz nr Paczkomatu lub adres, to wyślę mały upominek, także poza Polską! :)
    Dziękuje bardzo, jedna naklejka jest już nalepiona na monitorze :)
  • #5 21002510
    tomekgl
    Poziom 16  
    Piękny projekt. Tylko na jedną rzecz trzeba zwrócić uwagę, zwłaszcza gdyby ktoś inny niż autor chciał to wykorzystać bez wnikania w kod.
    Cytat:

    Tak, to działa bez rasberry pi. Jeżel home assistant jest wystawiony na zewnątrz, to dostęp do urządzenia jest nieograniczony

    Tak, nieograniczony również dla niepowołanych osób, brakuje w tej implementacji TLSa. Nigdy nie używajcie nieszyfrowanych protokołów poza swoją domową siecią albo użyjcie VPNa.
  • #6 21002824
    XS_Sowa
    Poziom 13  
    Dziękuje za komentarz :)

    Jeżeli moduł komunikuje się z Home Assistant i brokerem wewnątrz sieci, to wystawiając HA na zewnątrz, połączenie między telefonem a routerem jest szyfrowane i poza sieć żaden plaintext nie wychodzi :)

    Omawiany przypadek był by problemem jeżeli użyjemy zewnętrznego brokera. Zakładam jednak, że jeżeli ktoś ma możliwość uruchomienia Home Assistant lokalnie to odpalenie mosquito też nie stanowi problemu :)

    Tak czy inaczej, TLS miałem z tyłu głowy bo miejsca na procku zostało całkiem sporo, nie wykluczam, że dodam taką opcję gdy wgryzę się głębiej w LwIP. Narazie z wyżej wymienionych względów nie planuję tego robić.

    Aczkolwiek słuszna uwaga, bezpieczeństwo przede wszystkim, i z wewnętrzną siecią najlepiej łączyć się po VPN.

    Pozdrawiam :)
REKLAMA