Is Arduino running – Er døren låst?
(For English version press American Flag on top of Sidebar)
En bekendt spurgte, om jeg kunne være behjælpelig. Han vil gerne sikre sig, at døren hos hans mor er låst, når hjemmeplejen forlader hendes bolig. Han har installeret en kontakt, som er sluttet, når døren er låst og brudt, når døren er ulåst. Resten skulle jeg klare. Noget elektronik, så han kan få besked om tingenes tilstand ved døren.
Nemt, tænkte jeg. Blynk og Nano, et par ledninger til kontakten og en lysdiode, hvis nu herligheden skal i en kasse. Så kan man se status for Power On. Fritzing diagrammet kan næsten ikke være simplere:
I Blynk-app’en en rød og en grøn LED-widget, samt en lcd-widget for at få lidt liv på skærmen. Der skal ikke meget kode til for at få det hele til at fungere. Med SimpleTimer og lidt hensigtsmæssig kode skulle det også være muligt kun at sende informationer, når noget ændrer sig. Heller ikke en uoverkommelig opgave.
Men så let skulle jeg ikke slippe om ved det. For app’en viser i sagens natur altid blot den seneste information, som er blevet sendt til den. Derfor er det vigtigt at vide, om sketchen kører ovre på Nano’en. Hvis den er gået i stå, er det der står på skærmen værdiløst. Og hvis man ikke ved, om Nano’en er gået i stå, så……. Jeg oplevede også, at når min telefon havde været i dvale, var min skærm ikke altid opdateret, når den kom til live igen. Så den simple løsning var ganske enkelt ikke brugbar, før der blev bygget noget sikkerhed ind i sketchen.
Alt i alt fik jeg indkredset tre forhold, som der skal tages højde for i koden, for at app’en er pålidelig og anvendelig:
- Løbende information om Arduino er aktiv eller ej
- Sikre at app’en er opdateret, hvis Arduino har været nede, nettet har været ned, app’en slukket eller har været på dvale.
- En indikator på hardwaresiden, så man kan se, om der er forbindelse til net og Blynk-server.
1. ‘Arduino er aktiv’ indikator.
Det kan laves med en ny LED-widget, som jeg har koblet op på virtual pin V31. For at vise, at der er liv i Nano, skal den virtuelle LED blinke. Det klares med disse to små funktioner:
1 2 3 4 5 6 7 8 9 10 |
void setBlinkOn() { Blynk.virtualWrite(V31, 1023); } } void setBlinkOff() { Blynk.virtualWrite(V31, 0); } |
Med SimpleTimer times de i på denne måde i setup():
1 2 |
timer.setInterval(500, setBlinkOn); timer.setInterval(1000, setBlinkOff); |
Nu blinker min LED-widget, når Arduino kører. Hvis den ikke blinker, er det fordi forbindelsen til serveren er nede eller fordi min Arduino ikke kører. Så ved jeg, at jeg ikke kan stole på informationen på min skærm.
I sync eller ej?
Der findes forskellige måder at synkronisere på og jeg har forsøgt mig med en del af dem, som udviklerne bag Blynk anbefaler. Jeg har været omkring BLYNK_CONNECTED, syncAll() og syncVirtual(pin) men endte med blot at kalde min egen updateApp() funktion hver gang der er gået 30 sekunder. Ved samme lejlighed besluttede jeg, at der skal sendes en notifikation, når der sker ændringer. (Husk at give Blynk lov til at sende notifikationer til din smartphone!). Der kan højst sendes notifikationer hvert minut, så jeg valgte 90 sekunder for at være sikker på at få informationen frem. Igen sikrer SimpleTimer, at det sker:
1 2 |
timer.setInterval(30000, updateApp); timer.setInterval(90000, doNotify); |
Er Arduino connected?
Også her var jeg omkring forskellige løsninger men først efter at have læst koden i header-filerne Blynk.h og UIPEthernet.h fandt jeg en løsning. Jeg fandt frem til en PUBLIC metode, connected(), som kunne anvendes. Det blev skrevet sammen med mine tidligere blink-funktioner og ser således ud:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void setBlinkOn() { Blynk.virtualWrite(V31, 1023); if (Blynk.connected() == true) { digitalWrite(CONNECT_PIN, HIGH); } } void setBlinkOff() { Blynk.virtualWrite(V31, 0); digitalWrite(CONNECT_PIN, LOW); } |
På CONNECT_PIN sidder min LED, som egentlig var tænkt som indikator for power on. Nu blinker den i stedet, når Arduino er i kontakt med Blynk-serveren. Hvis forbindelsen bliver afbrudt, blinker dioden stadig videre et lille stykke tid. I min opsætning kommer der 9-10 hjerteslag, inden den slukker helt.
Blynk app
Som det ses ovenfor, har jeg følgende widgets i min app:
- LED på V29 (rød)
- LED på V30 (grøn)
- LED på V31 (blå)
- LCD på V1, – husk at sætte det til advanced mode
- Notify-widget, husk at tillade, at Blynk sender notifikationer på din smartphone.
That’s it.
Hele koden kan hentes her:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
/* CheckDoor version 1.02 Created by Jørgen Sand May 2016 and published under the GNU GPL as free software ------------------------------------------------ Blynk with Nano and ENC28J60 ethernet shield Blynk - assignment of the virtual PINs V29: LED door open V30: LED door locked V31: LED App is running */ //#define PRINT_SERIAL #ifdef PRINT_SERIAL #define BLYNK_PRINT Serial #endif #include #include #include //Constants const byte DOOR_PIN = 7; const byte CONNECT_PIN = 8; char auth[] = "4f0e787ca44245a2bc6a31cb500daff3"; boolean MemState = false; boolean DoorState = false; byte NotifyCase = 2; //default - nothing to report WidgetLCD lcd(V1); void doNotify() { switch (NotifyCase) { case 0: Blynk.notify("Døren er ÅBEN"); break; case 1: Blynk.notify("Døren er LÅST"); break; default: ; } NotifyCase = 2; } boolean changeInState(boolean CurrentState) { if (CurrentState == MemState) { return false; } else { #ifdef PRINT_SERIAL Serial.print("Old MemState: "); Serial.println(MemState); #endif MemState = CurrentState; return true; } } void updateApp() { boolean LockedDoor = (digitalRead(DOOR_PIN) == LOW);//goes low when activated if (LockedDoor == true) { { Blynk.virtualWrite(V29, 0); Blynk.virtualWrite(V30, 1023); lcd.print(4, 0, "Døren er"); lcd.print(4, 1, "LÅST"); } } else { Blynk.virtualWrite(V29, 1023); Blynk.virtualWrite(V30, 0); lcd.print(4, 0, "Døren er"); lcd.print(4, 1, "ÅBEN"); } } void checkDoor() { boolean LockedDoor = (digitalRead(DOOR_PIN) == LOW);//goes low when activated if (changeInState(LockedDoor) == true) { updateApp(); if (LockedDoor == true) { { NotifyCase = 1; } } else { NotifyCase = 0; } } #ifdef PRINT_SERIAL Serial.print("Status på låst dør: "); Serial.println(LockedDoor); #endif } void setBlinkOn() { Blynk.virtualWrite(V31, 1023); if (Blynk.connected() == true) { digitalWrite(CONNECT_PIN, HIGH); } } void setBlinkOff() { Blynk.virtualWrite(V31, 0); digitalWrite(CONNECT_PIN, LOW); } SimpleTimer timer; void setup() { pinMode(DOOR_PIN, INPUT_PULLUP); pinMode(CONNECT_PIN, OUTPUT); MemState = (digitalRead(DOOR_PIN) == LOW);//goes low when activated #ifdef PRINT_SERIAL Serial.begin(19200); Serial.println("Serial er startet..."); #endif Blynk.begin(auth); while (Blynk.connect() == false) { // wait.... } digitalWrite(CONNECT_PIN, HIGH); timer.setInterval(500, setBlinkOn); timer.setInterval(1000, setBlinkOff); timer.setInterval(1000, checkDoor); timer.setInterval(30000,updateApp); timer.setInterval(90000 , doNotify); //all widgets to NULL Blynk.virtualWrite(V29, 0); Blynk.virtualWrite(V30, 0); Blynk.virtualWrite(V31, 0); lcd.clear(); // updateApp(); } void loop() { timer.run(); Blynk.run(); }test |