Darba, is-sistemi ta 'awtomazzjoni tad-dar, jew "dar intelliġenti" kif spiss kienu jissejħu, kienu għaljin ħafna u s-sinjuri biss setgħu jaffordjawhom. Illum fis-suq tista 'ssib kits pjuttost rħas b'sensors, buttuni/swiċċijiet u attwaturi għall-kontroll tad-dawl, sokits, ventilazzjoni, provvista ta' ilma u konsumaturi oħra. U anke l-aktar persuna DIY mgħawweġ tista 'tinvolvi ruħha fis-sbuħija u tgħaqqad apparat għal dar intelliġenti bi prezz irħas.

Tipikament, l-apparati proposti huma jew sensuri jew attwaturi. Jagħmluha faċli biex jiġu implimentati xenarji bħal "meta jinxtegħel sensor tal-moviment, ixgħel id-dwal" jew "is-swiċċ ħdejn il-ħruġ jitfi d-dwal fl-appartament kollu." Imma b'xi mod l-affarijiet ma ħadmux bit-telemetrija. Fl-aħjar, huwa graff ta 'temperatura u umdità, jew qawwa istantanja fi żbokk speċifiku.
Dan l-aħħar installajt miters tal-ilma b'output tal-polz. Għal kull litru li jgħaddi mill-meter, is-swiċċ tal-qasab jiġi attivat u jagħlaq il-kuntatt. L-unika ħaġa li għad fadal hija li twaħħal mal-wajers u tipprova tikseb benefiċċju minnha. Pereżempju, analizza l-konsum tal-ilma skont is-siegħa u l-jum tal-ġimgħa. Ukoll, jekk hemm diversi risers ta 'l-ilma fl-appartament, allura huwa aktar konvenjenti li tara l-indikaturi attwali kollha fuq skrin wieħed milli titla' f'niċeċ diffiċli biex jintlaħqu bi flashlight.
Taħt il-qatgħa hemm il-verżjoni tiegħi ta 'apparat ibbażat fuq ESP8266, li jgħodd il-impulsi minn miters tal-ilma u jibgħat qari permezz tal-MQTT lis-server tad-dar intelliġenti. Aħna ser nipprogrammaw f'micropython bl-użu tal-librerija uasyncio. Meta ħoloq il-firmware, iltqajt ma 'diversi diffikultajiet interessanti, li se niddiskuti wkoll f'dan l-artikolu. Mur!
L-iskema

Il-qalba taċ-ċirkwit kollu hija modulu fuq il-mikrokontrollur ESP8266. ESP-12 kien oriġinarjament ippjanat, iżda tiegħi rriżulta li kien difettuż. Kellna nikkuntentaw bil-modulu ESP-07, li kien disponibbli. Fortunatament, huma l-istess kemm f'termini ta 'pinnijiet kif ukoll ta' funzjonalità, l-unika differenza hija fl-antenna - l-ESP-12 għandha waħda mibnija, filwaqt li l-ESP-07 għandha waħda esterna. Madankollu, anke mingħajr antenna WiFi, is-sinjal fil-kamra tal-banju tiegħi jasal b'mod normali.
Wiring tal-modulu standard:
- buttuna reset b'pull-up u capacitor (għalkemm it-tnejn diġà huma ġewwa l-modulu)
- Is-sinjal ta' attivazzjoni (CH_PD) jinġibed għall-enerġija
- GPIO15 jinġibed lejn l-art. Dan huwa meħtieġ biss fil-bidu, iżda għad m'għandi xejn x'nwaħħal ma' din is-sieq m'għadniex bżonnha
Biex tpoġġi l-modulu fil-modalità tal-firmware, għandek bżonn tagħmel short-circuit GPIO2 mal-art, u biex tagħmilha aktar konvenjenti, ipprovda buttuna Boot. F'kondizzjoni normali, dan il-pin jinġibed għall-enerġija.
L-istat tal-linja GPIO2 huwa ċċekkjat biss fil-bidu tat-tħaddim - meta tiġi applikata l-enerġija jew immedjatament wara reset. Allura l-modulu jew boots bħas-soltu jew jidħol fil-modalità firmware. Ladarba mgħobbija, dan il-pin jista 'jintuża bħala GPIO regolari. Ukoll, peress li diġà hemm buttuna hemmhekk, tista 'tehmeż xi funzjoni utli magħha.
Għall-ipprogrammar u d-debugging se nuża l-UART, li joħroġ għal moxt. Meta meħtieġ, sempliċiment nqabbad adapter USB-UART hemmhekk. Għandek bżonn biss li tiftakar li l-modulu huwa mħaddem minn 3.3V. Jekk tinsa taqleb l-adapter għal dan il-vultaġġ u tforni 5V, il-modulu x'aktarx jinħaraq.
M'għandi l-ebda problemi bl-elettriku fil-kamra tal-banju - l-iżbokk jinsab madwar metru mill-meters, għalhekk se nkun mħaddma b'220V. Bħala sors ta 'enerġija se jkolli żgħir minn Tenstar Robot. Personalment, għandi żmien diffiċli bl-elettronika analoga u tal-enerġija, iżda hawn provvista ta 'enerġija lesta f'każ żgħir.
Biex tindika l-modi operattivi, ipprovdejt LED konness ma 'GPIO2. Madankollu, ma ħallejthiex, għax... Il-modulu ESP-07 diġà għandu LED, u huwa wkoll imqabbad ma 'GPIO2. Imma ħalliha tkun fuq il-bord, f'każ li nixtieq joħroġ dan l-LED għall-każ.
Ejja ngħaddu għall-aktar parti interessanti. Il-miters tal-ilma m'għandhom l-ebda loġika; L-unika ħaġa disponibbli għalina hija l-impulsi - l-għeluq tal-kuntatti tas-swiċċ tal-qasab kull litru. L-outputs tiegħi tal-iswiċċ tal-qasab huma konnessi ma 'GPIO12/GPIO13. Se nippermetti r-reżistenza pull-up b'mod programmatiku ġewwa l-modulu.
Inizjalment, insejt nipprovdi resistors R8 u R9 u l-verżjoni tiegħi tal-bord ma għandhiexhom. Imma peress li diġà qed inpoġġi d-dijagramma biex jara kulħadd, ta 'min jikkoreġi din is-sorveljanza. Reżisturi huma meħtieġa sabiex ma jinħaraqx il-port jekk il-firmware glitches u jissettja l-pin għal wieħed, u l-iswiċċ tal-qasab shorts din il-linja għall-art (bir-reżistenza massimu ta '3.3V/1000Ohm = 3.3mA se jiċċirkola).
Wasal iż-żmien li taħseb x'għandek tagħmel jekk l-elettriku jintefa. L-ewwel għażla hija li titlob valuri inizjali tal-counter mis-server fil-bidu. Iżda dan ikun jeħtieġ kumplikazzjoni sinifikanti tal-protokoll tal-iskambju. Barra minn hekk, il-prestazzjoni tal-apparat f'dan il-każ tiddependi fuq l-istat tas-server. Jekk is-server ma bediex wara li l-enerġija tkun mitfija (jew bdiet aktar tard), il-miter tal-ilma ma jkunx jista 'jitlob valuri inizjali u ma jaħdimx b'mod korrett.
Għalhekk, iddeċidejt li nimplimenta l-iffrankar tal-valuri tal-kontro f'ċippa tal-memorja konnessa permezz tal-I2C. M'għandi l-ebda rekwiżiti speċjali għad-daqs tal-memorja flash - għandek bżonn biss li tiffranka numri 2 (in-numru ta 'litri skont il-miters tal-ilma sħun u kiesaħ). Anke l-iżgħar modulu se tagħmel. Imma trid tagħti attenzjoni għan-numru ta 'ċikli ta' reġistrazzjoni. Għall-biċċa l-kbira tal-moduli dan huwa 100 elf ċiklu, għal xi sa miljun.
Jidher li miljun huwa ħafna. Imma matul is-snin 4 li ngħix fl-appartament tiegħi, ikkunsmajt ftit aktar minn 500 metru kubu ta 'ilma, jiġifieri 500 elf litru! U 500 elf rekord fil-flash. U dak huwa biss ilma kiesaħ. Tista ', ovvjament, terġa' tissalda ċ-ċippa kull ftit snin, iżda jirriżulta li hemm ċipep FRAM. Mil-lat ta 'programmazzjoni, din hija l-istess EEPROM I2C, biss b'numru kbir ħafna ta' ċikli ta 'kitba mill-ġdid (mijiet ta' miljuni). Huwa biss li għadni ma nistax nasal fil-maħżen b'mikroċirkwiti bħal dawn, għalhekk għalissa l-24LC512 tas-soltu se joqgħod.
Bord ta 'ċirkwit stampat
Inizjalment, ippjanajt li nagħmel il-bord id-dar. Għalhekk, il-bord kien iddisinjat bħala naħa waħda. Imma wara li qattajt siegħa bil-ħadid tal-laser u maskra tal-istann (b'xi mod mhux comme il faut mingħajrha), xorta ddeċidejt li tordna l-bordijiet miċ-Ċiniżi.

Kważi qabel ma ordnat il-bord, indunajt li minbarra ċ-ċippa tal-memorja flash, stajt ngħaqqad xi ħaġa oħra utli għall-bus I2C, bħal display. X'għandu joħroġ eżattament għalih għadu mistoqsija, iżda jeħtieġ li jiġi mgħoddi fuq il-bord. Ukoll, peress li kont se tordna bordijiet mill-fabbrika, ma kien hemm l-ebda punt li nillimita ruħi għal bord b'naħa waħda, għalhekk il-linji I2C huma l-uniċi fuq in-naħa ta 'wara tal-bord.
Kien hemm ukoll problema waħda kbira bil-wiring one-way. Għax Il-bord kien imfassal bħala naħa waħda, għalhekk il-binarji u l-komponenti SMD kienu ppjanati li jitqiegħdu fuq naħa waħda, u l-komponenti tal-ħruġ, il-konnetturi u l-provvista tal-enerġija fuq in-naħa l-oħra. Meta rċevejt il-bordijiet xahar wara, insejt il-pjan oriġinali u issaldjat il-komponenti kollha fuq in-naħa ta 'quddiem. U biss meta ġie għall-issaldjar tal-provvista tal-enerġija rriżulta li l-plus u l-minus kienu wired bil-maqlub. Kelli razzett bil jumpers. Fl-istampa ta 'hawn fuq, diġà biddilt il-wajers, iżda l-art hija trasferita minn parti waħda tal-bord għal oħra permezz tal-labar tal-buttuna Boot (għalkemm ikun possibbli li titfassal binarju fuq it-tieni saff).
Irriżulta hekk

Djar
Il-pass li jmiss huwa l-ġisem. Jekk għandek printer 3D, din mhix problema. Ma ddejjaqtx wisq - ġibt biss kaxxa tad-daqs it-tajjeb u għamilt qtugħ fil-postijiet it-tajba. L-għata hija mwaħħla mal-ġisem b'viti żgħar li jimpenjaw ruħhom.

Diġà semmejt li l-buttuna Boot tista 'tintuża bħala buttuna għal skopijiet ġenerali - għalhekk aħna ser nuruha fuq il-pannell ta' quddiem. Biex tagħmel dan, ġibt "bir" speċjali fejn tgħix il-buttuna.

Ġewwa l-kaxxa hemm ukoll studs li fuqhom il-bord huwa installat u mwaħħal b'kamin M3 wieħed (ma kienx hemm aktar spazju fuq il-bord)
Għażilt il-wiri diġà meta stampajt l-ewwel verżjoni tal-kampjun tal-każ. Qarrej standard b'żewġ linji ma kienx jidħol f'dan il-każ, iżda fil-qiegħ kien hemm display OLED SSD1306 128 × 32. Huwa daqsxejn żgħir, imma m'għandix għalfejn inħares lejha kuljum—hija wisq għalija.
B'dan il-mod u dak kif il-wajers se jiġu mgħoddija minnha, iddeċidejt li twaħħal il-wiri fin-nofs tal-kaxxa. L-ergonomija, ovvjament, hija taħt il-par - il-buttuna hija fuq nett, il-wiri huwa fil-qiegħ. Imma diġà għedt li l-idea li twaħħal id-displej waslet tard wisq u kont għażżien wisq biex nerġa’ nwaħħal il-bord biex iċċaqlaq il-buttuna.
L-apparat huwa mmuntat. Il-modulu tal-wiri huwa inkollat mal-snot b'kolla sħuna


Ir-riżultat finali jista' jidher fuq KDPV
Firmware
Ejja ngħaddu għall-parti tas-softwer. Għal snajja żgħar bħal din, inħobb ħafna nuża Python () - il-kodiċi jirriżulta li huwa kompatt ħafna u jinftiehem. Fortunatament, m'hemmx għalfejn tinżel fil-livell tar-reġistru sabiex tagħfas il-mikrosekondi - kollox jista 'jsir minn Python.
Jidher li kollox huwa sempliċi, iżda mhux sempliċi ħafna - l-apparat għandu diversi funzjonijiet indipendenti:
- L-utent ipoġġi l-buttuna u jħares lejn il-wiri
- Litri jimmarka u jaġġorna l-valuri fil-memorja flash
- Il-modulu jimmonitorja s-sinjal WiFi u jerġa 'jikkonnettja jekk meħtieġ
- Ukoll, mingħajr bozza tad-dawl teptip huwa impossibbli
Ma tistax tassumi li funzjoni waħda ma ħadmitx jekk waħda oħra hija mwaħħla għal xi raġuni. Diġà kelli l-mili tal-kakti fi proġetti oħra u issa għadni nara glitches fl-istil ta’ “tilfet litru ieħor għax il-wiri kien qed jaġġorna f’dak il-mument” jew “l-utent ma jista’ jagħmel xejn waqt li l-modulu jkun qed jikkonnettja ma’ Wifi." Naturalment, xi affarijiet jistgħu jsiru permezz ta 'interruzzjonijiet, iżda tista' tidħol f'limitazzjonijiet fuq it-tul, it-tbejjit ta 'sejħiet, jew bidliet mhux atomiċi għall-varjabbli. Ukoll, il-kodiċi li jagħmel kollox malajr jinbidel f'mush.
В Użajt multitasking preventiv klassiku u FreeRTOS, iżda f'dan il-każ il-mudell irriżulta li kien ħafna aktar adattat . Barra minn hekk, l-implimentazzjoni Python ta 'coroutines hija sempliċement aqwa - kollox isir b'mod sempliċi u konvenjenti għall-programmatur. Ikteb il-loġika tiegħek stess, għidli f'liema postijiet tista' taqleb bejn il-flussi.
Nissuġġerixxi li tistudja d-differenzi bejn multitasking preventiv u kompetittiv bħala suġġett fakultattiv. Issa ejja fl-aħħar nimxu fuq il-kodiċi.
#####################################
# Counter class - implements a single water counter on specified pin
#####################################
class Counter():
debounce_ms = const(25)
def __init__(self, pin_num, value_storage):
self._value_storage = value_storage
self._value = self._value_storage.read()
self._value_changed = False
self._pin = Pin(pin_num, Pin.IN, Pin.PULL_UP)
loop = asyncio.get_event_loop()
loop.create_task(self._switchcheck()) # Thread runs foreverKull counter huwa mmaniġġjat minn istanza tal-klassi Counter. L-ewwelnett, il-valur tal-counter inizjali jitnaqqas mill-EEPROM (value_storage) - dan huwa kif jiġi realizzat l-irkupru wara nuqqas ta 'enerġija.
Il-pin huwa inizjalizzat b'pull-up integrat għall-provvista tal-enerġija: jekk is-swiċċ tal-qasab ikun magħluq, il-linja hija żero, jekk il-linja tkun miftuħa, tinġibed sal-provvista tal-enerġija u l-kontrollur jaqra waħda.
Hawnhekk huwa mniedi wkoll kompitu separat, li se jeżamina l-pin. Kull counter se jmexxi l-kompitu tiegħu stess. Hawn hu l-kodiċi tagħha
""" Poll pin and advance value when another litre passed """
async def _switchcheck(self):
last_checked_pin_state = self._pin.value() # Get initial state
# Poll for a pin change
while True:
state = self._pin.value()
if state != last_checked_pin_state:
# State has changed: act on it now.
last_checked_pin_state = state
if state == 0:
self._another_litre_passed()
# Ignore further state changes until switch has settled
await asyncio.sleep_ms(Counter.debounce_ms)Dewmien ta' 25ms huwa meħtieġ biex jiġi ffiltrat il-bounce tal-kuntatt, u fl-istess ħin jirregola kemm-il darba l-kompitu jinxtegħel (filwaqt li dan il-kompitu jkun qed jorqod, kompiti oħra jkunu qed jaħdmu). Kull 25ms il-funzjoni tqum, tiċċekkja l-pin u jekk il-kuntatti tas-swiċċ tal-qasab huma magħluqa, imbagħad ikun għadda litru ieħor mill-meter u dan jeħtieġ li jiġi pproċessat.
def _another_litre_passed(self):
self._value += 1
self._value_changed = True
self._value_storage.write(self._value)L-ipproċessar tal-litru li jmiss huwa trivjali - il-counter sempliċement jiżdied. Ukoll, ikun sabiħ li tikteb il-valur il-ġdid fuq flash drive.
Għal faċilità ta 'użu, "aċċessorji" huma pprovduti
def value(self):
self._value_changed = False
return self._value
def set_value(self, value):
self._value = value
self._value_changed = FalseUkoll, issa ejja nieħdu vantaġġ mid-delights ta 'Python u l-librerija uasync u nagħmlu oġġett counter waitable (kif nistgħu nittraduċu dan għar-Russu? Dak li tista' tistenna?)
def __await__(self):
while not self._value_changed:
yield from asyncio.sleep(0)
return self.value()
__iter__ = __await__ Din hija funzjoni tant konvenjenti li tistenna sakemm il-valur tal-kontro jiġi aġġornat - il-funzjoni tqum minn żmien għal żmien u tiċċekkja l-bandiera _value_changed. Il-ħaġa friska ta 'din il-funzjoni hija li l-kodiċi tas-sejħa jista' torqod waqt li jsejjaħ din il-funzjoni u jorqod sakemm jiġi riċevut valur ġdid.
Xi ngħidu dwar l-interruzzjonijiet?Iva, f'dan il-punt tista 'trollni, tgħid li int stess għidt dwar l-interruzzjonijiet, imma fir-realtà għamilt stħarriġ tal-pin stupid. Fil-fatt l-interruzzjonijiet huma l-ewwel ħaġa li ppruvajt. Fl-ESP8266, tista 'torganizza interruzzjoni tarf, u anke tikteb handler għal din l-interruzzjoni f'Python. F'din l-interruzzjoni, il-valur ta' varjabbli jista' jiġi aġġornat. Probabbilment, dan ikun biżżejjed jekk il-counter kien apparat slave - wieħed li jistenna sakemm jintalab dan il-valur.
Sfortunatament (jew fortunatament?) It-tagħmir tiegħi huwa attiv, għandu hu stess jibgħat messaġġi permezz tal-protokoll MQTT u jikteb id-dejta fl-EEPROM. U hawnhekk jidħlu r-restrizzjonijiet - ma tistax talloka memorja f'interruzzjonijiet u tuża munzell kbir, li jfisser li tista 'tinsa li tibgħat messaġġi fuq in-netwerk. Hemm pasti bħal micropython.schedule() li jippermettulek tmexxi xi funzjoni "malajr possibbli", iżda tqum il-mistoqsija, "x'inhu l-punt?" X'jiġri jekk qed nibagħtu xi tip ta 'messaġġ bħalissa, u mbagħad tidħol interruzzjoni u tħassar il-valuri tal-varjabbli. Jew, pereżempju, wasal counter value ġdid mis-server filwaqt li konna ma konna ma nkitbux dak l-antik. B'mod ġenerali, għandek bżonn timblokka s-sinkronizzazzjoni jew toħroġ minnha b'xi mod differenti.
U minn żmien għal żmien RuntimeError: skeda munzell ħabtiet sħiħa u min jaf għaliex?
B'votazzjoni espliċita u uasync, f'dan il-każ b'xi mod jirriżulta aktar sabiħ u affidabbli
Ġibt xogħol bl-EEPROM għal klassi żgħira
class EEPROM():
i2c_addr = const(80)
def __init__(self, i2c):
self.i2c = i2c
self.i2c_buf = bytearray(4) # Avoid creation/destruction of the buffer on each call
def read(self, eeprom_addr):
self.i2c.readfrom_mem_into(self.i2c_addr, eeprom_addr, self.i2c_buf, addrsize=16)
return ustruct.unpack_from("<I", self.i2c_buf)[0]
def write(self, eeprom_addr, value):
ustruct.pack_into("<I", self.i2c_buf, 0, value)
self.i2c.writeto_mem(self.i2c_addr, eeprom_addr, self.i2c_buf, addrsize=16)F'Python, huwa diffiċli li taħdem direttament mal-bytes, iżda huma l-bytes li jinkitbu fil-memorja. Kelli nagħmel il-konverżjoni bejn integer u bytes billi tuża l-librerija ustruct.
Sabiex ma tittrasferixxix l-oġġett I2C u l-indirizz taċ-ċellula tal-memorja kull darba, imgeżwer kollox fi klassika żgħira u konvenjenti
class EEPROMValue():
def __init__(self, i2c, eeprom_addr):
self._eeprom = EEPROM(i2c)
self._eeprom_addr = eeprom_addr
def read(self):
return self._eeprom.read(self._eeprom_addr)
def write(self, value):
self._eeprom.write(self._eeprom_addr, value)L-oġġett I2C innifsu huwa maħluq b'dawn il-parametri
i2c = I2C(freq=400000, scl=Pin(5), sda=Pin(4))Niġu għall-aktar parti interessanti - l-implimentazzjoni tal-komunikazzjoni mas-server permezz tal-MQTT. Ukoll, m'hemmx bżonn li jiġi implimentat il-protokoll innifsu - sibt fuq l-Internet . Dan huwa dak li se nużaw.
L-aktar affarijiet interessanti kollha jinġabru fil-klassi CounterMQTTClient, li hija bbażata fuq il-librerija MQTTClient. Nibdew mill-periferija
#####################################
# Class handles both counters and sends their status to MQTT
#####################################
class CounterMQTTClient(MQTTClient):
blue_led = Pin(2, Pin.OUT, value = 1)
button = Pin(0, Pin.IN)
hot_counter = Counter(12, EEPROMValue(i2c, EEPROM_ADDR_HOT_VALUE))
cold_counter = Counter(13, EEPROMValue(i2c, EEPROM_ADDR_COLD_VALUE))Hawnhekk tista 'toħloq u tikkonfigura pinnijiet u buttuni tal-bozoz tad-dawl, kif ukoll oġġetti tal-miter tal-ilma kiesaħ u sħun.
Bl-inizjalizzazzjoni, mhux kollox huwa daqshekk trivjali
def __init__(self):
self.internet_outage = True
self.internet_outages = 0
self.internet_outage_start = ticks_ms()
with open("config.txt") as config_file:
config['ssid'] = config_file.readline().rstrip()
config['wifi_pw'] = config_file.readline().rstrip()
config['server'] = config_file.readline().rstrip()
config['client_id'] = config_file.readline().rstrip()
self._mqtt_cold_water_theme = config_file.readline().rstrip()
self._mqtt_hot_water_theme = config_file.readline().rstrip()
self._mqtt_debug_water_theme = config_file.readline().rstrip()
config['subs_cb'] = self.mqtt_msg_handler
config['wifi_coro'] = self.wifi_connection_handler
config['connect_coro'] = self.mqtt_connection_handler
config['clean'] = False
config['clean_init'] = False
super().__init__(config)
loop = asyncio.get_event_loop()
loop.create_task(self._heartbeat())
loop.create_task(self._counter_coro(self.cold_counter, self._mqtt_cold_water_theme))
loop.create_task(self._counter_coro(self.hot_counter, self._mqtt_hot_water_theme))
loop.create_task(self._display_coro())Biex jiġu stabbiliti l-parametri operattivi tal-librerija mqtt_as, jintuża dizzjunarju kbir ta 'settings differenti - config. Ħafna mis-settings default huma tajbin għalina, iżda ħafna settings jeħtieġ li jiġu stabbiliti b'mod espliċitu. Sabiex ma nikteb is-settings direttament fil-kodiċi, naħżenhom fil-fajl tat-test config.txt. Dan jippermettilek tibdel il-kodiċi irrispettivament mis-settings, kif ukoll irbattu diversi apparati identiċi b'parametri differenti.
L-aħħar blokk ta 'kodiċi jibda diversi coroutines biex iservu diversi funzjonijiet tas-sistema. Per eżempju, hawnhekk hija coroutine li s-servizzi counters
async def _counter_coro(self, counter, topic):
# Publish initial value
value = counter.value()
await self.publish(topic, str(value))
# Publish each new value
while True:
value = await counter
await self.publish_msg(topic, str(value))Il-korrutina tistenna f'linja għal valur ta' kontro ġdid u, hekk kif jidher, tibgħat messaġġ permezz tal-protokoll MQTT. L-ewwel biċċa tal-kodiċi tibgħat il-valur inizjali anki jekk l-ebda ilma ma jgħaddi mill-counter.
Il-klassi bażi MQTTClient isservi lilha nnifisha, tibda konnessjoni WiFi u terġa 'tikkonnettja meta tintilef il-konnessjoni. Meta jkun hemm bidliet fl-istat tal-konnessjoni WiFi, il-librerija tinformana billi ċċempel lil wifi_connection_handler
async def wifi_connection_handler(self, state):
self.internet_outage = not state
if state:
self.dprint('WiFi is up.')
duration = ticks_diff(ticks_ms(), self.internet_outage_start) // 1000
await self.publish_debug_msg('ReconnectedAfter', duration)
else:
self.internet_outages += 1
self.internet_outage_start = ticks_ms()
self.dprint('WiFi is down.')
await asyncio.sleep(0)Il-funzjoni hija kkupjata b'mod onest minn eżempji. F'dan il-każ, jgħodd in-numru ta' qtugħ (internet_outages) u t-tul tagħhom. Meta l-konnessjoni tiġi restawrata, jintbagħat ħin idle lis-server.
Mill-mod, l-aħħar irqad huwa meħtieġ biss biex il-funzjoni tkun asinkronika - fil-librerija tissejjaħ permezz ta 'wait, u jistgħu jissejħu biss funzjonijiet li l-ġisem tagħhom fih await ieħor.
Minbarra l-konnessjoni mal-WiFi, għandek bżonn ukoll li tistabbilixxi konnessjoni mas-sensar MQTT (server). Il-librerija tagħmel dan ukoll, u jkollna l-opportunità li nagħmlu xi ħaġa utli meta tiġi stabbilita l-konnessjoni
async def mqtt_connection_handler(self, client):
await client.subscribe(self._mqtt_cold_water_theme)
await client.subscribe(self._mqtt_hot_water_theme)Hawnhekk aħna tabbona għal diversi messaġġi - is-server issa għandu l-abbiltà li jissettja l-valuri kurrenti tal-counter billi jibgħat il-messaġġ korrispondenti.
def mqtt_msg_handler(self, topic, msg):
topicstr = str(topic, 'utf8')
self.dprint("Received MQTT message topic={}, msg={}".format(topicstr, msg))
if topicstr == self._mqtt_cold_water_theme:
self.cold_counter.set_value(int(msg))
if topicstr == self._mqtt_hot_water_theme:
self.hot_counter.set_value(int(msg))Din il-funzjoni tipproċessa messaġġi deħlin, u skont is-suġġett (titlu tal-messaġġ), il-valuri ta 'wieħed mill-counters huma aġġornati
Koppja ta' funzjonijiet helper
# Publish a message if WiFi and broker is up, else discard
async def publish_msg(self, topic, msg):
self.dprint("Publishing message on topic {}: {}".format(topic, msg))
if not self.internet_outage:
await self.publish(topic, msg)
else:
self.dprint("Message was not published - no internet connection")Din il-funzjoni tibgħat messaġġ jekk il-konnessjoni tkun stabbilita. Jekk ma jkunx hemm konnessjoni, il-messaġġ jiġi injorat.
U din hija biss funzjoni konvenjenti li tiġġenera u tibgħat messaġġi ta 'debugging.
async def publish_debug_msg(self, subtopic, msg):
await self.publish_msg("{}/{}".format(self._mqtt_debug_water_theme, subtopic), str(msg))
Tant test, u għadna ma blinknex LED. Hawn
# Blink flash LED if WiFi down
async def _heartbeat(self):
while True:
if self.internet_outage:
self.blue_led(not self.blue_led()) # Fast blinking if no connection
await asyncio.sleep_ms(200)
else:
self.blue_led(0) # Rare blinking when connected
await asyncio.sleep_ms(50)
self.blue_led(1)
await asyncio.sleep_ms(5000)Jien ipprovdejt 2 modi ta' teptip. Jekk il-konnessjoni tintilef (jew għadha qed tiġi stabbilita), l-apparat se jteptep malajr. Jekk il-konnessjoni tiġi stabbilita, l-apparat iteptep darba kull 5 sekondi. Jekk meħtieġ, modi oħra ta' teptip jistgħu jiġu implimentati hawn.
Iżda l-LED huwa biss pampering. Immirajna wkoll lejn il-wiri.
async def _display_coro(self):
display = SSD1306_I2C(128,32, i2c)
while True:
display.poweron()
display.fill(0)
display.text("COLD: {:.3f}".format(self.cold_counter.value() / 1000), 16, 4)
display.text("HOT: {:.3f}".format(self.hot_counter.value() / 1000), 16, 20)
display.show()
await asyncio.sleep(3)
display.poweroff()
while self.button():
await asyncio.sleep_ms(20)Dan huwa dak li kont qed nitkellem dwaru - kemm huwa sempliċi u konvenjenti bil-coroutines. Din il-funzjoni żgħira tiddeskrivi l-esperjenza tal-utent KOLLHA. Il-koroutine sempliċement jistenna li l-buttuna tiġi ppressata u tixgħel il-wiri għal 3 sekondi. Il-wiri juri l-qari kurrenti tal-miter.
Għad fadal ftit affarijiet żgħar. Hawn hi l-funzjoni li (re) tibda din l-intrapriża kollha. Il-linja prinċipali biss tibgħat diversi informazzjoni tad-debugging darba kull minuta. B'mod ġenerali, nikkwotaha kif inhi - ma naħsibx li hemm bżonn li tikkummenta wisq
async def main(self):
while True:
try:
await self._connect_to_WiFi()
await self._run_main_loop()
except Exception as e:
self.dprint('Global communication failure: ', e)
await asyncio.sleep(20)
async def _connect_to_WiFi(self):
self.dprint('Connecting to WiFi and MQTT')
sta_if = network.WLAN(network.STA_IF)
sta_if.connect(config['ssid'], config['wifi_pw'])
conn = False
while not conn:
await self.connect()
conn = True
self.dprint('Connected!')
self.internet_outage = False
async def _run_main_loop(self):
# Loop forever
mins = 0
while True:
gc.collect() # For RAM stats.
mem_free = gc.mem_free()
mem_alloc = gc.mem_alloc()
try:
await self.publish_debug_msg("Uptime", mins)
await self.publish_debug_msg("Repubs", self.REPUB_COUNT)
await self.publish_debug_msg("Outages", self.internet_outages)
await self.publish_debug_msg("MemFree", mem_free)
await self.publish_debug_msg("MemAlloc", mem_alloc)
except Exception as e:
self.dprint("Exception occurred: ", e)
mins += 1
await asyncio.sleep(60)Ukoll, ftit aktar settings u kostanti biex tlesti d-deskrizzjoni
#####################################
# Constants and configuration
#####################################
config['keepalive'] = 60
config['clean'] = False
config['will'] = ('/ESP/Wemos/Water/LastWill', 'Goodbye cruel world!', False, 0)
MQTTClient.DEBUG = True
EEPROM_ADDR_HOT_VALUE = const(0)
EEPROM_ADDR_COLD_VALUE = const(4)Kollox jibda hekk
client = CounterMQTTClient()
loop = asyncio.get_event_loop()
loop.run_until_complete(client.main())Ġrat xi ħaġa fil-memorja tiegħi
Allura, il-kodiċi kollu qiegħed hemm. I uploaded il-fajls bl-użu ta ' l-utilità ampy - li jippermettilek ittellgħuhom fuq il-flash drive intern (dik fl-ESP-07 innifsu) u mbagħad aċċess għaliha mill-programm bħala fajls normali. Hemmhekk tellajt ukoll l-mqtt_as, uasyncio, ssd1306 u l-libreriji tal-kollezzjonijiet li użajt (użajt ġewwa mqtt_as).
Inniedu u... Ikollna MemoryError. Barra minn hekk, aktar ma ppruvajt nifhem fejn eżattament il-memorja kienet qed tnixxi, aktar ma poġġiet stampi tad-debug, iktar qabel deher dan l-iżball. Tfittxija qasira fuq Google wasslitni biex nifhem li l-mikrokontrollur għandu, fil-prinċipju, biss 30 kB ta 'memorja, li fiha 65 kB ta' kodiċi (inklużi libreriji) sempliċement ma jistgħux jidħlu.
Imma hemm mod kif toħroġ. Jirriżulta li micropython ma jesegwixxix kodiċi direttament minn fajl .py - dan il-fajl jiġi kkompilat l-ewwel. Barra minn hekk, huwa miġbur direttament fuq il-mikrokontrollur, mibdul f'bytecode, li mbagħad jinħażen fil-memorja. Ukoll, biex il-kompilatur jaħdem, għandek bżonn ukoll ċertu ammont ta 'RAM.
Il-trick huwa li tiffranka l-mikrokontrollur minn kumpilazzjoni intensiva fir-riżorsi. Tista 'tiġbor il-fajls fuq kompjuter kbir u ttella' l-bytecode lest fil-mikrokontrollur. Biex tagħmel dan, għandek bżonn tniżżel il-firmware micropython u tibni .
Ma ktibtx Makefile, iżda manwalment għadda u kkumpilat il-fajls kollha meħtieġa (inklużi l-libreriji) xi ħaġa bħal din
mpy-cross water_counter.pyLi jibqa 'huwa li ttella' fajls bl-estensjoni .mpy, mingħajr ma ninsew li l-ewwel tħassar il-.py korrispondenti mis-sistema tal-fajls tal-apparat.
Għamilt l-iżvilupp kollu fil-programm (IDE?) ESPlorer. Jippermettilek ittella skripts fuq il-mikrokontrollur u tesegwixxihom immedjatament. Fil-każ tiegħi, il-loġika kollha u l-ħolqien tal-oġġetti kollha jinsabu fil-fajl water_counter.py (.mpy). Iżda sabiex dan kollu jibda awtomatikament, irid ikun hemm ukoll fajl imsejjaħ main.py fil-bidu. Barra minn hekk, għandu jkun eżattament .py, u mhux .mpy ikkumpilat minn qabel. Hawn huma l-kontenut trivjali tiegħu
import water_counterInnieduha - kollox jaħdem. Iżda l-memorja ħielsa hija żgħira b'mod allarmanti - madwar 1kb. Għadni pjanijiet biex nespandi l-funzjonalità tal-apparat, u dan il-kilobyte huwa ċar li mhux biżżejjed għalija. Iżda rriżulta li hemm mod kif ukoll għal dan il-każ.
Hawn il-ħaġa. Anke jekk il-fajls huma kkompilati f'bytecode u jirrisjedu fuq is-sistema tal-fajls interna, fir-realtà xorta huma mgħobbija fir-RAM u esegwiti minn hemm. Iżda jirriżulta li micropython jista 'jesegwixxi bytecode direttament mill-memorja flash, iżda għal dan għandek bżonn tibniha direttament fil-firmware. Mhux diffiċli, għalkemm dam pjuttost żmien fuq in-netbook tiegħi (hemm biss inzerta li kelli Linux).
L-algoritmu huwa bħal dan:
- Niżżel u installa . Din il-ħaġa tiġbor kompilatur u libreriji għal programmi għall-ESP8266. Immuntat skont l-istruzzjonijiet fuq il-paġna ewlenija tal-proġett (għażilt is-setting STANDALONE=iva)
- Download
- Poġġi l-libreriji meħtieġa fil-portijiet/esp8266/moduli ġewwa s-siġra tal-micropython
- Aħna niġbru l-firmware skont l-istruzzjonijiet fil-fajl
- Intellgħu l-firmware fuq il-mikrokontrollur (nagħmel dan fuq il-Windows bl-użu tal-programmi ESP8266Flasher jew Python esptool)
Dak hu, issa 'importazzjoni ssd1306' se tneħħi l-kodiċi direttament mill-firmware u RAM mhux se jiġi kkunsmat għal dan. B'dan il-trick, tellajt biss il-kodiċi tal-librerija fil-firmware, filwaqt li l-kodiċi tal-programm prinċipali jiġi esegwit mis-sistema tal-fajls. Dan jippermettilek timmodifika faċilment il-programm mingħajr ma tikkompila mill-ġdid il-firmware. Fil-mument għandi madwar 8.5kb ta 'RAM ħielsa. Dan se jippermettilna nimplimentaw pjuttost ħafna funzjonalità utli differenti fil-futur. Ukoll, jekk ma jkunx hemm biżżejjed memorja għal kollox, allura tista 'timbotta l-programm prinċipali fil-firmware.
Allura x'għandna nagħmlu dwarha issa?
Ok, il-ħardwer huwa issaldjat, il-firmware huwa miktub, il-kaxxa hija stampata, l-apparat huwa mwaħħla mal-ħajt u heureusement teptip bozza tad-dawl. Imma għalissa hija kollha kaxxa sewda (litteralment u figurattivament) u għadha ta’ ftit użu. Wasal iż-żmien li tagħmel xi ħaġa bil-messaġġi MQTT li jintbagħtu lis-server.
Id-“dar intelliġenti” tiegħi qed iddur . Il-modulu MQTT jew joħroġ mill-kaxxa, jew jiġi installat faċilment mis-suq add-on - ma niftakarx minn fejn ġibtu. MQTT mhix ħaġa awtosuffiċjenti - għandek bżonn hekk imsejħa. sensar - server li jirċievi, jagħżel u jgħaddi messaġġi MQTT lill-klijenti. Jien nuża mosquitto, li (bħal majordomo) jimxi fuq l-istess netbook.
Wara li l-apparat jibgħat messaġġ mill-inqas darba, il-valur jidher immedjatament fil-lista.

Dawn il-valuri issa jistgħu jiġu assoċjati ma 'oġġetti tas-sistema, jistgħu jintużaw fi skripts ta' awtomazzjoni u suġġetti għal diversi analiżi - li kollha huma lil hinn mill-ambitu ta 'dan l-artikolu. Nista' nirrakkomanda s-sistema majordomo lil kull min hu interessat — ħabib qed jibni wkoll dar intelliġenti u jitkellem b'mod ċar dwar it-twaqqif tas-sistema.
Ser nuruk ftit graffs. Din hija grafika sempliċi ta 'valuri ta' kuljum

Wieħed jista 'jara li kważi ħadd ma uża l-ilma bil-lejl. Ftit drabi xi ħadd mar it-tojlit, u jidher li l-filtru tar-reverse osmosis terda ftit litri kull lejl. Filgħodu, il-konsum jiżdied b'mod sinifikanti. Normalment nuża l-ilma minn bojler, iżda mbagħad ridt nieħu banju u bdejt temporanjament għall-ilma sħun tal-belt - dan huwa wkoll viżibbli b'mod ċar fil-graff tal-qiegħ.
Minn din il-grafika tgħallimt li biex tmur it-tojlit teħtieġ 6-7 litri ta 'ilma, li tieħu doċċa teħtieġ 20-30 litru, il-ħasil tal-platti teħtieġ madwar 20 litru, u li tieħu banju teħtieġ 160 litru. Il-familja tiegħi tikkonsma xi mkien madwar 500-600 litru kuljum.
Għal dawk li huma speċjalment kurjużi, tista 'tħares lejn ir-rekords għal kull valur individwali

Minn hawn tgħallimt li meta l-vit ikun miftuħ, l-ilma jgħaddi b'veloċità ta 'madwar 1 litru kull 5 s.
Iżda f'din il-forma l-istatistika probabbilment ma tkunx konvenjenti ħafna biex tħares lejha. Majordomo għandu wkoll il-kapaċità li jara mapep tal-konsum skont il-ġurnata, il-ġimgħa u x-xahar. Hawnhekk, pereżempju, hemm grafika tal-konsum f'vireg

S'issa għandi data biss għal ġimgħa. F'xahar, din il-grafika tkun aktar indikattiva - kull jum ikollu kolonna separata. L-istampa hija kemmxejn mħassra mill-aġġustamenti għall-valuri li ndaħħal manwalment (l-akbar kolonna). U għadu mhux ċar jekk issettjax ħażin l-ewwel valuri, kważi kubu inqas, jew jekk dan huwiex bug fil-firmware u mhux il-litri kollha ġew magħduda. Bżonn aktar ħin.
Il-grafiċi nfushom għadhom jeħtieġu xi magic, whitewashing, pittura. Forsi se nibni wkoll graff tal-konsum tal-memorja għal skopijiet ta 'debugging, f'każ li xi ħaġa tkun qed tnixxi hemmhekk. Forsi b'xi mod se nuri perjodi meta ma kienx hemm l-Internet. Għalissa, dan kollu huwa fil-livell tal-ideat.
Konklużjoni
Illum l-appartament tiegħi sar ftit aktar intelliġenti. B'apparat daqshekk żgħir, ikun aktar konvenjenti għalija li timmonitorja l-konsum tal-ilma fid-dar. Jekk qabel kont indignat għal "mill-ġdid, kkunsmajna ħafna ilma f'xahar," issa nista 'nsib is-sors ta' dan il-konsum.
Xi wħud jistgħu jsibuha stramba li jħarsu lejn il-qari fuq l-iskrin jekk ikun metru 'l bogħod mill-meter innifsu. Iżda fil-futur mhux imbiegħed, qed nippjana li nimxi għal appartament ieħor, fejn se jkun hemm diversi risers tal-ilma, u l-meters infushom x'aktarx ikunu jinsabu fuq l-inżul. Allura apparat ta 'qari mill-bogħod se jkun utli ħafna.
Nippjana wkoll li nkabbar il-funzjonalità tal-apparat. Diġà qed inħares lejn valvi motorizzati. Issa, biex taqleb il-bojler għall-ilma tal-belt, għandi bżonn indawwar 3 viti f'niċċa diffiċli biex tintlaħaq. Ikun ħafna aktar konvenjenti li tagħmel dan b'buttuna waħda bl-indikazzjoni korrispondenti. Ukoll, ovvjament, ta 'min timplimenta protezzjoni kontra tnixxijiet.
Fl-artiklu ddeskrivejt il-verżjoni tiegħi ta' apparat ibbażat fuq ESP8266. Fl-opinjoni tiegħi, ħarġt b'verżjoni interessanti ħafna tal-firmware micropython bl-użu ta 'coroutines - sempliċi u sbieħ. Ippruvajt niddeskrivi ħafna mill-sfumaturi u n-nuqqasijiet li ltqajt magħhom matul il-kampanja. Forsi ddeskrivejt kollox f’wisq dettall personalment, bħala qarrej, huwa aktar faċli għalija li naqbeż l-affarijiet bla bżonn milli wara naħseb dak li baqa’ ma ntqalx;
Bħal dejjem, jien miftuħ għal kritika kostruttiva.
Sors: www.habr.com
