poniedziałek, 25 sierpnia 2025

Hacking Tuya Smart sprinkler / irrigation controller

There are not many dedicated sprinkler controllers on the internet that can be integrated with Home Assistant. Moreover, most available electromagnetic valves use AC, which creates the problem of needing an additional power supply to get them working. Nowadays, you can buy DC coils (for example, Hunter makes some), but they are much more expensive.

Solution used so far.

Previously, I used a modified LILYGO T-Relay with an external WiFi antenna. It worked reliably, but as mentioned, it required a DC power supply for the T-Relay and AC for the coils. After a few years of reliable operation, I added another watering section to my garden. However, since I used a T-Relay with 4 relays and none were free anymore, I needed to find a new solution.

New possible solutions:

Additional Relay:

The ESP32 board has enough GPIOs to control many more relays, but due to the external DC PSU, I ran out of space in the hermetic box. Buying a new one was not an option because the old one was already too big.

Design own PCB:

Years ago, I designed my own PCBs, but now I’m older, lazier, and don’t have as much time. Like the previous proposal, this idea was also rejected.

Find an Out-of-the-Box Solution:

Solutions from big companies are usually very expensive and often cannot be integrated with Home Assistant.
After days of searching online, I was unable to find any suitable solution for controlling 24 ACV valves over ZigBee. Moreover, WiFi-based solutions are also limited to Tuya Cloud.

Summary.

It is very hard to find a solution that fits the needs of cloud-independent home automation.

Experiment.

During research for another project, I found that it’s possible to bypass Tuya Cloud using different tools, so I decided to buy a controller like the one shown below.
When it arrived, I decided to disassemble it. The front acrylic panel is glued with thin double-sided tape, so to remove it, you need to use a thin knife and carefully pry off the panel.

Inside, there is a CBU unit. After some research, I found that it can be flashed with ESPHome, so I decided to try it. I also found a place for a U.FL connector, so I used an external WiFi antenna because the device is located in a metal enclosure.

To flash the CBU unit, you have to solder cables or use a 3D-printed adapter called the Tuya CBU Flashing Jig

These are the results of all those operations


ESPHome

Now it was time for some reverse engineering and coding. I spent a few hours testing and tweaking the code, and here is the resulting configuration, which supports the controller’s LED indicators and touch buttons.

esphome:
name: "smart-sprinkler"
friendly_name: "smart-sprinkler"

bk72xx:
board: cbu

# Enable logging
logger:

# Enable Home Assistant API
api:
encryption:
key: ""

ota:
- platform: esphome
password: ""

wifi:
ssid: !wifi_iot_ssid
password: !wifi_iot_password

# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Smart-sprinkler Fallback Hotspot"
password: ""
fast_connect: True


captive_portal:

# Configure shift registers
sn74hc595:
- id: 'sn74hc595_hub'
data_pin: GPIO9
clock_pin: GPIO15
latch_pin: GPIO17
sr_count: 2
- id: 'sn74hc595_relay_hub'
data_pin: GPIO16
clock_pin: GPIO22
latch_pin: GPIO20
sr_count: 2


output:
- platform: gpio
id: status_led_1
pin:
sn74hc595: sn74hc595_hub
number: 0
inverted: true

- platform: template
type: binary
id: status_led_1_temp
write_action:
- while:
condition:
lambda: return (state > 0);
then:
- output.turn_on: status_led_1
- delay: 500ms
- output.turn_off: status_led_1
- delay: 500ms
- output.turn_off: status_led_1

- platform: gpio
id: status_led_2
pin:
sn74hc595: sn74hc595_hub
number: 1
inverted: true
- platform: template
type: binary
id: status_led_2_temp
write_action:
- while:
condition:
lambda: return (state > 0);
then:
- output.turn_on: status_led_2
- delay: 500ms
- output.turn_off: status_led_2
- delay: 500ms
- output.turn_off: status_led_2

- platform: gpio
id: status_led_3
pin:
sn74hc595: sn74hc595_hub
number: 2
inverted: true
- platform: template
type: binary
id: status_led_3_temp
write_action:
- while:
condition:
lambda: return (state > 0);
then:
- output.turn_on: status_led_3
- delay: 500ms
- output.turn_off: status_led_3
- delay: 500ms
- output.turn_off: status_led_3

- platform: gpio
id: status_led_4
pin:
sn74hc595: sn74hc595_hub
number: 3
inverted: true
- platform: template
type: binary
id: status_led_4_temp
write_action:
- while:
condition:
lambda: return (state > 0);
then:
- output.turn_on: status_led_4
- delay: 500ms
- output.turn_off: status_led_4
- delay: 500ms
- output.turn_off: status_led_4

- platform: gpio
id: status_led_5
pin:
sn74hc595: sn74hc595_hub
number: 4
inverted: true
- platform: template
type: binary
id: status_led_5_temp
write_action:
- while:
condition:
lambda: return (state > 0);
then:
- output.turn_on: status_led_5
- delay: 500ms
- output.turn_off: status_led_5
- delay: 500ms
- output.turn_off: status_led_5

- platform: gpio
id: status_led_6
pin:
sn74hc595: sn74hc595_hub
number: 5
inverted: true
- platform: template
type: binary
id: status_led_6_temp
write_action:
- while:
condition:
lambda: return (state > 0);
then:
- output.turn_on: status_led_6
- delay: 500ms
- output.turn_off: status_led_6
- delay: 500ms
- output.turn_off: status_led_6

- platform: gpio
id: status_led_7
pin:
sn74hc595: sn74hc595_hub
number: 6
inverted: true
- platform: template
type: binary
id: status_led_7_temp
write_action:
- while:
condition:
lambda: return (state > 0);
then:
- output.turn_on: status_led_7
- delay: 500ms
- output.turn_off: status_led_7
- delay: 500ms
- output.turn_off: status_led_7
- platform: gpio
id: status_led_8
pin:
sn74hc595: sn74hc595_hub
number: 7
inverted: true
- platform: template
type: binary
id: status_led_8_temp
write_action:
- while:
condition:
lambda: return (state > 0);
then:
- output.turn_on: status_led_8
- delay: 500ms
- output.turn_off: status_led_8
- delay: 500ms
- output.turn_off: status_led_8
- platform: gpio
pin: 28
id: led_wifi
inverted: true

interval:
- interval: 1s
then:
if:
condition:
wifi.connected:
then:
- output.turn_on: led_wifi
else:
- output.turn_off: led_wifi
# Interval for closing cycle of choosing valves
- interval: 120s
then:
if:
condition:
lambda: !lambda |-
if (id(valve_id)){
return true;
}
return false;
then:
lambda: !lambda |-
id(recover_status_led).execute();
id(valve_id) = 0;

# Valves configuratin
switch:
- platform: gpio
name: valve_1
id: valve_1
pin:
sn74hc595: sn74hc595_relay_hub
number: 0
on_turn_on:
- output.turn_on: status_led_1
on_turn_off:
- output.turn_off: status_led_1
- platform: gpio
name: valve_2
id: valve_2
pin:
sn74hc595: sn74hc595_relay_hub
number: 1
on_turn_on:
- output.turn_on: status_led_2
on_turn_off:
- output.turn_off: status_led_2
- platform: gpio
name: valve_3
id: valve_3
pin:
sn74hc595: sn74hc595_relay_hub
number: 2
on_turn_on:
- output.turn_on: status_led_3
on_turn_off:
- output.turn_off: status_led_3
- platform: gpio
name: valve_4
id: valve_4
pin:
sn74hc595: sn74hc595_relay_hub
number: 3
on_turn_on:
- output.turn_on: status_led_4
on_turn_off:
- output.turn_off: status_led_4
- platform: gpio
name: valve_5
id: valve_5
pin:
sn74hc595: sn74hc595_relay_hub
number: 4
on_turn_on:
- output.turn_on: status_led_5
on_turn_off:
- output.turn_off: status_led_5
- platform: gpio
name: valve_6
id: valve_6
pin:
sn74hc595: sn74hc595_relay_hub
number: 5
on_turn_on:
- output.turn_on: status_led_6
on_turn_off:
- output.turn_off: status_led_6
- platform: gpio
name: valve_7
id: valve_7
pin:
sn74hc595: sn74hc595_relay_hub
number: 6
on_turn_on:
- output.turn_on: status_led_7
on_turn_off:
- output.turn_off: status_led_7
- platform: gpio
name: valve_8
id: valve_8
pin:
sn74hc595: sn74hc595_relay_hub
number: 7
on_turn_on:
- output.turn_on: status_led_8
on_turn_off:
- output.turn_off: status_led_8
- platform: gpio
name: motor
id: motor
pin:
number: 24


globals:
# Variable used for switch case to choose valve using buttons
- id: valve_id
type: int
restore_value: no
initial_value: '0'


#Physical buttons configuration with actions
binary_sensor:
- platform: gpio
id: back
pin:
number: 7
mode:
input: true
pullup: true
on_press:
then:
lambda: !lambda |-
id(recover_status_led).execute();
id(valve_id) = (id(valve_id) - 1);
id(blink_status_led).execute();
- platform: gpio
id: forward
pin:
number: 6
mode:
input: true
pullup: true
on_press:
then:
lambda: !lambda |-
id(recover_status_led).execute();
id(valve_id) = (id(valve_id) + 1);
id(blink_status_led).execute();
- platform: gpio
id: play
pin:
number: 8
mode:
input: true
pullup: true
on_press:
then:
script.execute: toogle_valve
- platform: gpio
id: config
pin:
number: 26
mode:
input: true
pullup: true
on_press:
then:
lambda: !lambda |-
id(recover_status_led).execute();
id(valve_id) = 0;

script:
# Restore previous status of led
- id: recover_status_led
then:
lambda: !lambda |-
switch (id(valve_id)){
case 1:
id(status_led_1_temp).turn_off();
if (id(valve_1).state){
id(status_led_1).turn_on();
}
break;
case 2:
id(status_led_2_temp).turn_off();
if (id(valve_2).state){
id(status_led_2).turn_on();
}
break;
case 3:
id(status_led_3_temp).turn_off();
if (id(valve_3).state){
id(status_led_3).turn_on();
}
break;
case 4:
id(status_led_4_temp).turn_off();
if (id(valve_4).state){
id(status_led_4).turn_on();
}
break;
case 5:
id(status_led_5_temp).turn_off();
if (id(valve_5).state){
id(status_led_5).turn_on();
}
break;
case 6:
id(status_led_6_temp).turn_off();
if (id(valve_6).state){
id(status_led_6).turn_on();
}
break;
case 7:
id(status_led_7_temp).turn_off();
if (id(valve_7).state){
id(status_led_7).turn_on();
}
break;
case 8:
id(status_led_8_temp).turn_off();
if (id(valve_8).state){
id(status_led_8).turn_on();
}
break;
}
# Blink single status led choosen using buttons
- id: blink_status_led
then:
lambda: !lambda |-
switch (id(valve_id)){
case 1:
id(status_led_1_temp).turn_on();
break;
case 2:
id(status_led_2_temp).turn_on();
break;
case 3:
id(status_led_3_temp).turn_on();
break;
case 4:
id(status_led_4_temp).turn_on();
break;
case 5:
id(status_led_5_temp).turn_on();
break;
case 6:
id(status_led_6_temp).turn_on();
break;
case 7:
id(status_led_7_temp).turn_on();
break;
case 8:
id(status_led_8_temp).turn_on();
break;
default:
id(valve_id) = 0;
break;
}

- id: toogle_valve
then:
lambda: !lambda |-
switch (id(valve_id)){
case 1:
id(valve_1).toggle();
break;
case 2:
id(valve_2).toggle();
break;
case 3:
id(valve_3).toggle();
break;
case 4:
id(valve_4).toggle();
break;
case 5:
id(valve_5).toggle();
break;
case 6:
id(valve_6).toggle();
break;
case 7:
id(valve_7).toggle();
break;
case 8:
id(valve_8).toggle();
break;
}

poniedziałek, 21 września 2020

Mikrus - koncept drukarki na paskach i PFTE #1

 Jakiś czas temu przeglądając forum zauważyłem iż większość narzekań jest na krzywe śruby trapezowe powodujące artefakty. Aby rozwiązać ten problem wiele osób zaleca drogie śruby kulowe. Ale znaleźli się też tacy co próbowali użyć pasków do napędzania osi Z. Co więcej większość doświadczonych zamiast wałków poleca prowadnice liniowe. Idąc tym tropem dalej natknąłem się na różne próby użycia PTFE jako ślizgacze i zrobienia z nich czegoś na wzór prowadnic liniowych.

Patrząc na swoją kolekcję części zapasowych oraz bazując na informacjach zbieranych w trakcie czytania niezmierzonych pokładów wątków postanowiłem zrobić eksperyment(?). Mianowicie zaprojektować małą biurkową drukarkę. O to jej główne założenia:

  • Wykorzystać jak najwięcej zalegających części w domu.
  • Mała i zgrabna (woła roboczego już mam).
  • Układ kartezjański.
  • Wykorzystać ramę jako prowadnice (?).
  • Wszystko na paskach.
Powstało coś takiego:

Jest to wciąż prototypowa wersja już nieco nie aktualna, ale nie miałem czasu poprawić plików "assembly".

Teraz tak trochę w liczbach co udało mi się osiągnąć.

  • Drukarka ma wymiary po obrysie 250x314 mm a pole w X Y mam 160x140 mm - oś X ma potwierdzone już 160mm natomiast oś Y jeszcze nie testowana. Dla porównania w moim HEVO przy obrysie 485x475mm mam pole robocze w okolicach 300x300mm co daje stały współczynnik strat w osi X 185 dla hevo i 90 dla mikrusa oraz Y 175 dla hevo oraz 174 dla mikrusa. Uważam że jest to dość dobry wynik.
  • Prędkości obecnie są niewielkie, na osi Y do 200mm/s a na X do 100mm/s. Wynika to z różnych rozdzielczości na osiach. W X jest to 160 kroków na mm a w Y 80 kroków na mm. Wszysto na chwilę obecną zasilane jest z 12V. Jeżeli ktoś jest zainteresowany większą ilością szczegółów to zapraszam do Dobór silników krokowych
  • Użyłem profili aluminiowych 15x15x2mm na belce X oraz na stole są one 1,5mm grubości.
A tak na chwilę obecną przedstawiają się postępy prac nad nią:

 




















CDN...

piątek, 10 lipca 2020

W poszukiwaniu idealnego koloru do litofanów #1

W swojej przygodzie z drugiem 3D dotarłem do miejsca gdzie napotkałem coś takiego jak litofan. W skrócie jest to płytka o różnej grubości która po oświetleniu z tyłu pokazuje co skrywa,

Najpopularniejszym kolorem do litofanów jest biały. Jednak z tym białym bywa różnie. Generalnie jest to jeden z najtrudniejszych kolorów do opanowania. Jest to związane z tym iż biały pigment kryje najsłabiej i potrzeba go relatywnie więcej do uzyskania pożądanego koloru. Również w zależności od użytego barwnika bywa różnie. Polecam artykuł Understanding the ‘Science’ of Color

Swojego czasu nabyłem od Rosa3D szpulę PLA Premium przejściową gdzie tak z 80% stanowił kolor biały. Więc postanowił dać mu szansę i spróbować. Efekt mnie zaskoczył. Nie dość iż drukowało się nim bardzo przyjemnie to jeszcze litofan wyszedł bardzo ładny.


Więc postanowiłem iść za ciosem, skoro PLA dobrze się drukuje to stwierdziłem, że spróbuję z PET-G. Tak do lamp. Odpowiedz otrzymałem szybko. Dowiedziałem się z niej, że każdy filament PLA ze stajni R3D posiada taki sam rodzaj  i ilość białego barwnika, ale już PET-G posiada inny specyficzny dla danego typu polimeru. Więc poprosiłem o próbki i je też otrzymałem.


Więc w zasadzie tego samego dnia wrzuciłem próbkę do drukarki i taki jest efekt. Niestety było to wrzucone bez dopasowania profilu oraz jak się później okazało, prześwity oraz dziwnie położone warstwy spowodowane był problemem ze spadającą skarpetą głowicy. Wydruk jest "śliski" i ładnie błyszczący,
.

Tu jest DD biały, który przy szybkim drukowaniu dalej sprawia mi problemy.




Podsumowanie.

Jak widać na niżej załączonych obrazkach filamenty te posiadają różne pigmenty dające inne efekty. Oba PLA po "prześwietleniu" mają kolory sepii. DD jest ciemniejsze przy tych samych parametrach, natomiast R3D jaśniejsze. Zwiększyć przejście kolorów da się poprzez zwiększenie maksymalnej grubości w generatorze litofanów. PET-G wyszło w odcieniach szarości. W zależności od potrzeb można uzyskać różne efekty.
R3D PET-G
R3D PLA
DD PLA



Biały białemu nierówny.

Jednak jeżeli przyglądnąć się bliżej, to biały białemu nie równy.

PETG, R3D PLA, DD PLA
Tutaj zestawienie wszystkich próbek jeszcze raz.
Próbki białe i naturalne, w tel PLA DD białe,

środa, 21 marca 2018

Smary i oleje - czyli o "ślizgaczach" zbiór informacji

Uwaga:

Dane zawarte w publikacji są orientacyjne a oznaczenie iż dany smar/olej jest przeznaczony w danym kontakcie nie wyklucza użycia go w innych sytuacjach. Również należy pamiętać, że różne substancje zawarte w smarach/olejach mogą różnie oddziaływać na rodzaje plastiku. Celowo nie używam słów olej i smar, gdyż oba różnią się głównie stanem skupienia, ewentualnie pozostałymi parametrami w zależności od producenta.



metal-metal metal-plastik plastik-plastik Główne zastosowanie
Litowy X łożyska toczne i ślizgowe
Silikonowy X X smarowanie łożysk i przekładni z tworzyw sztucznych
Teflonowy X X X smarowanie suche, antyadhezyjne
Miedziany X przeciwzapieczeniowy, śruby i nakrętki
Grafitowy X przeciwzatarciowy, elementy narażone na warunki atmosferyczne
Maszynowy X lekko obciążonych części maszyn wymagających smarowania
Molibdenowy X odmiana litowego
Ceramiczny X połączeń narażonych na działanie dużego nacisku i wysokich temperatur
Wazelina techniczna X X X lekko obciążone elementy mechaniczne


 Litowy - w odmianie łożyskowej:
  • do smarowania łożysk tocznych i ślizgowych wszelkich maszyn w normalnych warunkach pracy
  • odporny na działanie wody i utlenianie
  • chroni przed zużyciem i korozją
  • wydłuża żywotność łożysk
  • możliwość pracy w temperaturze od -25°C do 220°C (w zależności od producenta)
  •  łożyska narażone na wibracje
  •  łożyska wysokoobrotowe narażone na działanie wysokich temperatur i wody
  •  łożyska średnio- i wysokoobrotowe
 Silikonowy:
  • odporny na temperatury od -180°C do +260°C (chwilowo) (w zależności od producenta)
  •  nie plami i nie klei się z kurzem
  •  idealny do użytku na styku powierzchni wykonanych z tworzywa sztucznego
  •  smarowanie czyste w przemyśle tekstylnym, papierniczym, spożywczym
  •  urządzenia elektryczne i energetyczne (zabezpieczenie toru prądu)
  •  przemysł motoryzacyjny – do smarowania linek w pancerzach, zamków, zawiasów, tulei i śrub
  •  posiada atest PZH w przemyśle spożywczym
  •  zabezpieczania gumowych elementów jak wycieraczki czy uszczelki
 Teflonowy:
  •  temperatura stosowania od -60°C do +230°C (w zależności od producenta)
  •  nie przyciąga brudu i kurzu
  •  trwale odporny na wodę, kwasy i zasady
  •  zapobiega piszczeniu, trzaskom i zacięciom
  •  zapewnia długoterminową ochronę przed zużyciem
  •  suche smarowanie
  •  w przypadku średniego obciążenia może być stosowany do metali, tworzyw sztucznych, kauczuku itp.
  •  idealny do przesuwanych dachów, szyn foteli, zawiasów i zamków drzwi, drzwi rozsuwanych, okien podwieszanych, zamków okien, zawiasów mebli, szuflad, prowadnic, łożysk kulkowych, przełączników elektrycznych itp.
  •  może spełniać rolę środka antyadhezyjnego
 Miedziany:
  • temperatura stosowania od -30°C do 1200°C (w zależności od producenta)
  • chroni przed zużyciem ciernym, korozją i wysokimi temperaturami
  • ciężko obciążone łożyska wszelkiego typu
  • połączenia gwintowe i wszelkie powierzchnie dopasowane - śruby, nakrętki i inne łączniki
  • używany w lutownicach starszej generacji do poprawy przewodnictwa cieplnego między grzałką a grotem
  • przewodność elektryczna(?)

 Grafitowy:
  • temperatura stosowania od -30°C do +600°C (w zależności od producenta)
  • wysoka przewodność elektryczna
  •  wysoka odporność na obciążenia
  •  wysoka odporność na działanie wody
  •  doskonała przylegalność w wysokich temperaturach, nadająca właściwości suchego smarowania grafitem
  •  otwarte przekładnie
  • smarowanie ogólne (szczególnie smarowe elementów narażonych na warunki atmosferyczne)
 Maszynowy:
  • temperatura stosowania od -30°C do +160°C (w zależności od producenta)
  • mieszalny z większością innych typowych smarów i olejów
  • odporny na wilgoć, temperaturę i zanieczyszczenia
  • smarowanie lekko obciążonych łożysk ślizgowych, kulkowych i rolkowych, łożysk kół, przegubów homokinetycznych, elementów nadwozi pojazdów oraz przekładni zębatych obciążonych udarowo
 Molibdenowy:
  • temperatura stosowania od -25°C do +150°C (w zależności od producenta)
  •  wysoka stabilność temperaturowa
  •  odporność na wilgoć
  •  smarowania przegubów, zwrotnic, łożysk, wałów i innych mechanizmów
 Ceramiczny:
  • odpowiedni do wysokich temperatur (nawet do 1400°C) (w zależności od producenta)
  • działa antykorozyjnie
  • zapobiega zapiekaniu się połączeń ze stali nierdzewnej
  • odporny na działanie kwasów i wody
  • Nie zawiera metali
Wazelina techniczna
  • środek smarny do lekko obciążonych węzłów tarcia jak: zamki, kłódki, zawiasy, narzędzia i różnego rodzaju maszyny
  • zabezpiecza przed sklejaniem i przymarzaniem uszczelek gumowych
  • zabezpiecza i natłuszcza wyroby skórzane
  • chroni przed korozją elementy i powierzchnie metalowe
  • konserwuje styki elektryczne, końcówki biegów akumulatora, zaciski przewodów samochodowych
  • zabezpiecza broń, złącza śrubowe, prowadnice itp

Źródła:

Głównie strony producentów smarów i olejów dostępnych w Polsce.