Víkendový projekt: Bezklíčové otevírání domovních dveří
Cíl: Nemuset u vchodu do domu hledat klíče, ale "nechat si zabzučet" vhodným vyzváněním na svůj zvonek. Prostředí: Domovní telefon MaT Elektra 8802 s elektrickým otvíračem dveří. Řešení: Do domácího telefonu vestavět zařízení, které bude vyhodnocovat "vzorec" zvonění a v případě rozpoznání očekávané poslupnosti simuluje stisk tlačítka pro otevírání dveří. Realizace: Arduino Pro Mini 5V/16MHz, reléový modul, pár pasivních součástek, 9V baterka. Výběr komponent motivován snahou o rychlý HW i SW vývoj i za cenu zjevného přezbrojení (overkillu). Odkazy: Zapojení telefonu: http://www.matelektra.cz/servis/schemata/ 1131_8802_nv818.htm, Reléový modul: http://www.hwkitchen.com/ products/electronic-brick-5v-relay-module-digital-/
Schéma zapojení
Použito Arduino Pro Mini ve verzi 5V, 16MHz pro napěťovou slučitelnost s použitým reléovým modulem. Svorky telefonu jsou na schématu označeny t0, t3 a t9. Fialová část: Napájení 9V baterkou, které lehce pomáhá jednocestně usměrněných a odporovým děličem snížených 12V získaných ze svorky 9 telefonu. Tuto svorku nelze příliš zatěžovat, neboť slouží pro otevírání dveří jejím spojením se zemí a odebíraný proud tedy prochází elektromagnetem otvírače. Červená část: Detekce zvonění. Při zvonění je zde audiosignál přiváděný do sluchátka. Jednocestně usměrněn, napětí sníženo děličem, omezeno zenerovou diodou a filtrováno kondenzátorem. Pulz na vstupu 2 Arduina nejprve vzbudí procesor ze spánku a následně je měřena délka jednotlivých zvonění. Zelená část: Reléový modul. Při logické jedničce na výstupu 6 Arduina sepne relé a svým kontaktem spojí svorku 9 telefonu na zem. Tím aktivuje otvítač dveří. Hnědá část: Indikace probuzení Arduina ze spánku. Vestavěná dioda: Indikuje rozpoznané zvonění.
Montáž do telefonu Kupodivu se v telefonu nachází skvělé místo pro zacvaknutí 9V baterie do výlisků v plastu. Ostatní části byly umístěny na vhodná volná místa. Arduino a pasivní součástky byly naletovány na univerzální plošný spoj. Reléový modul ponechán samostatně.
ToDo Vzorec zvonění je zadrátován do aplikace. Lepší by bylo jej uvést například jako řetězec pro snadnější parametrizaci. Nebo dokonce zavést učící režim, kdy lze vzorec zařízení naučit.
Ladění aplikace Seriový port je využit pro výstup ladících informací o délce pulzů a jejich vyhodnocení. Pokud tedy zařízení detekuje vyzvánění, ale neotevírá, pak je možné zjistit, co se mu nelíbí pohledem na sériovou konzoli. Jen pozor - zařízení je galvanicky spojeno se systémem domovního telefonu. Trochu jsem se bojím vyrovnávacích proudů v případě špatně uzeměného napaječe a tak jsem počítač připojoval jen když zařízení není připojeno k telefonu.
Poznámka Tento popis byl vytvořen pomocí aplikace Notable na iPadu. Kupodivu se moje původní naděje, že kreslení fancy schématu bude rychlé a zábavé a stejně rychlé jako na papír nenaplnila. Kapacitní displeje se pro kresnení něčeho alespoň rámcově přesného nehodí.
As-is disclaimer: Toto je rámcový popis řešení, které mi týden pěkně funguje. Pokud se necháte tímto dokumentem inspirovat a něco si poškodíte, tak za mnou nechoďte.
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
//Hardcoded ringing pattern is .-- (short, long, long ringing) #include
#include #define MAX_PIN_COUNT 22 const int pinRing = 2; //Ringing detector const int pinLed = 13; //Ringing indication const int pinLed2 = 5; //Waken up indicator const int pinRele = 6; //Door opener //Time constants in milliseconds const unsigned long minShort = 20; const unsigned long maxShort = 200; const unsigned long minLong = 350; const unsigned long maxLong = 700; const unsigned long maxPause = 1000; void ledOn() { digitalWrite(pinLed, HIGH); } void ledOff() { digitalWrite(pinLed, LOW); } void led2On() { digitalWrite(pinLed2, HIGH); } void led2Off() { digitalWrite(pinLed2, LOW); } void releOn() { digitalWrite(pinRele, HIGH); } void releOff() { digitalWrite(pinRele, LOW); } void wakeUp(){ } void delay1s() { delay(1000); }
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
void doSleep() { led2Off(); attachInterrupt(0, wakeUp, HIGH); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); ADCSRA &= ~(1 << ADEN); power_all_disable(); sleep_mode(); sleep_disable(); detachInterrupt(0); power_all_enable(); led2On(); } unsigned long measureLength() { unsigned long firstTime = millis(); unsigned long lastTime = firstTime; while( (millis() - lastTime) < 100) { if(digitalRead(pinRing) == HIGH) { lastTime = millis(); } } return lastTime - firstTime; } void waitForRing() { while(digitalRead(pinRing) == LOW) ; } boolean isShortRing(unsigned long howLong) { if( (howLong < maxShort) && (howLong > minShort) ) return true; return false; } boolean isLongRing(unsigned long howLong) { if( (howLong < maxLong) && (howLong > minLong) ) return true; return false; } unsigned long measurePause() { unsigned long firstTime = millis(); while( (millis() - firstTime) < maxPause) {
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
if(digitalRead(pinRing) == HIGH) { return millis() - firstTime; } } return 0; } // SETUP ----------------------------------------------- void setup() { unsigned short int pin; // Put all pins into output mode and low state for (pin = 0; pin < MAX_PIN_COUNT; pin++) { pinMode(pin,OUTPUT); digitalWrite(pin,LOW); } pinMode(pinRing, INPUT); // Check outputs ledOn(); delay1s(); ledOff(); led2On(); delay1s(); led2Off(); releOn(); delay1s(); releOff(); Serial.begin(9600); //Serial output for debug purposes } // LOOP ----------------------------------------------- unsigned long howLong; void loop() { Serial.println("Try it!" ); delay1s(); doSleep(); ledOn(); howLong = measureLength(); Serial.println(howLong); ledOff();
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
if( ! isShortRing(howLong) ) { Serial.println("Not short!" ); delay1s(); return; } howLong = measurePause(); Serial.println(howLong); if(howLong == 0) { Serial.println("Pause too long!"); delay1s(); return; } ledOn(); howLong = measureLength(); Serial.println(howLong); ledOff(); if( ! isLongRing(howLong) ) { Serial.println("Not long!" ); delay1s(); return; } howLong = measurePause(); Serial.println(howLong); if(howLong == 0) { Serial.println("Pause too long!" ); delay1s(); return; } ledOn(); howLong = measureLength(); Serial.println(howLong); ledOff(); if( ! isLongRing(howLong) ) { Serial.println("Not long!" ); delay1s(); return; } if(howLong != 0) {
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
Serial.println("This ringing is not expected!" ); delay1s(); return; } delay1s(); releOn(); delay(3000); releOff(); delay1s(); }