Добрый вечер уважаемые читатели сайта Voltrans. Сегодня я расскажу вам о новом проекте, который занял меня на выходные. Есть у меня резервный генератор, который работает на природном газе. Когда отключают электричество мне приходится идти в сарай и заводить его. Процесс довольно-таки несложный и в основном связан с манипуляцией кранами линии газа и поворотом замка зажигания, да + включением одного автомата для подачи электроэнергии от генератора в домашнюю сеть. Но не смотря на это это жутко не удобно переть, к примеру, в 2 часа ночи при минусовой температуре одним зимним утром в сарай, хотя он и не так уж далеко, всего в 50и с лишним метрах от жилища и заводить его. Конечно можно автоматизировать процесс, чем я и занимаюсь время от времени, но не закончив один проект перехожу к другому, как это часто и бывает. Но не в этот раз!
И так, пораскинув мозгами и запасшись терпением я разбил процесс автоматизации на несколько частей и устройств, что бы по частям решить проблему. Первое, что мне предстояло решить – это как открывать вентиль газа, который стоит около дома в 50и метрах от сарая? Благо времени у меня было пара деньков, и никто меня не беспокоил и за пару этих дней мне удалось собрать полноценное, функциональное устройство, которое не только открывает и закрывает задвижку, а еще дополнительно посылает ответ на запрос и данные от датчика температуры (за окном) и оставшийся заряд встроенного аккумулятора и еще многое другое…
Как, а вот об этом я вам и расскажу в подробностях ниже.
И так, что нам понадобится для начала:
1) Сама задвижка, естественно она должна быть с сервоприводом, благо такие есть в нашем магазине с соответствующем разделе.
2) Два радио модуля на 315, либо 433Мгц (желательно брать те, которуе можно будет потом использовать и в других проектах “умного дома”, чтобы соединить все устройства в дальнейшем воедино)
3) плата Ардуино Нано, можно и мини про, но там для перепрограммирования надо будет таскаться по всем устройствам с ТТЛ модулем, что не удобно, да и разница в цене не такая уж и большая + места у нас будет много, так что выбираем только комфортные решения.
4) 2х-цветный светодиод, можно и два разных цветов, если нет одного двухцветного, что бы он сигнализировал нам о открытом и закрытом положениях вентиля.
5) Кнопка для локального управления устройством, правда я в последствии от него отказался и прилепил мембранную 6и кнопочную клавиатуру.
6) Бипер – можно использовать любой динами из-под детских игрушек
7) Литий-ионная батарея от старого мобильника либо чего-либо еще не важно какой емкости, но желательно что бы был больше 350и миллиампер, ну что бы устройство могло автономно проработать хотя бы часов 10
8) Плата защиты/зарядки АКБ из пункта 7
9) Солнечная батарея (это не обязательно, можно использовать и зарядное устройство от мобильника на 5В, если рядом есть розетка электросети)
10) Датчик температуры MF58, я использовал терморезистор в стеклянном корпусе (тоже найдете в нашем магазине если что), несколько пассивных элементов: резисторы и один шотки диод для солнечной панели.
11) Плата мостовая для управления двигателями постоянного тока, к примеру L9110 вполне подойдет, она такая красненькая внизу…
12) удлинитель USB, хотя можно обойтись и одним разъемом + кабелем от мыши, можно и без этого обойтись пункта, если длина стандартного кабеля вентиля устраивает…
13) Какая нибудь коробочка для укладки и оформления всего этого добра!
что и как выглядит можете увидеть ниже на фотке. Там нет разве что резисторов и мембранной клавиатуры, но о них ниже…
Ну и поехали…
Паяем это все по ниже приведенной схеме:
в начале у меня получилось вот так, буквально на коленях 🙂
Далее заливаем скетчи для приемника (нашего устройства) и передатчика команд (собранный на макете двойник нашего устройства)
за исключением того, что тут нет задвижки и индикаторов, но есть две кнопочки, одна посылаем команду на открывание, другая на закрывание.
Скетч приемника:
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 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 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
/* RadioValve_V1.0 This sketch is for 433(315)Mhz transeiver modules hooked-Up to Arduino, L9110 and Valve Actuator to be controlled remotely. For Circuit diagram please visit http://www.voltrans.az/blablabla algorithm is the following: Each device shoud have unique 5digit deviceID, control module has 10001 deviceID as by default(can be whatever you wish) modified 7 Jan 2016 by Elik745i */ #include <Vcc.h> #include <VirtualWire.h> #include <EasyTransferVirtualWire.h> #include <EEPROM.h> const float VccMin = 3.3; // Minimum expected Vcc level, in Volts. const float VccMax = 4.2; // Maximum expected Vcc level, in Volts. const float VccCorrection = 4.2/4.3; // Measured Vcc by multimeter divided by reported Vcc //virtualwire____________________________________________________________________________________________________________ unsigned int unique_device_id = 0; //create object const int deviceID = 10002; //Unique Device ID const int packetID = 111; //Unique packet ID const int destinationID = 10001; EasyTransferVirtualWire ET; char buf[120]; struct SEND_DATA_STRUCTURE{ //наша структура данны. она должна быть определена одинаково на приёмнике и передатчике //кроме того, размер структуры не должен превышать 26 байт (ограничение VirtualWire) unsigned int device_id; unsigned int destination_id; unsigned int packet_id; byte command; int data; }; //переменная с данными нашей структуры SEND_DATA_STRUCTURE mydata; //ниже пару функций для записи данных типа unsigned int в EEPROM void EEPROMWriteInt(int p_address, unsigned int p_value) { byte lowByte = ((p_value >> 0) & 0xFF); byte highByte = ((p_value >> 8) & 0xFF); EEPROM.write(p_address, lowByte); EEPROM.write(p_address + 1, highByte); } unsigned int EEPROMReadInt(int p_address) { byte lowByte = EEPROM.read(p_address); byte highByte = EEPROM.read(p_address + 1); return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00); } //_____________________________________________________________________________________________________________________ Vcc vcc(VccCorrection); const int butt = A4; //buttons const int temp = A5; const int receive_pin = 2; const int buzz = 4; // Buzzer PIN const int irgr = 5; // OPEN (green) LED const int irbs = 6; // LED base PIN, PWM brightness control const int irrd = 7; // OPEN (green) LED const int vlvc = 8; // Valve Closed Switch const int vlvo = 9; // Valve Open Switch const int vopn = 13; // Valve Open PIN const int transmit_pin = 12; const int vcpn = 11; // Valve Close PIN const int irbr = 50; // LED brightness (0-254) float Temp = 0; int alarm = 0; int ledState = 0; unsigned long previousMillis = 0; const long interval = 5000; int vstatus = 0; // the setup function runs once when you press reset or power the board void setup() { Serial.begin(57600); pinMode(irrd, OUTPUT); pinMode(irbs, OUTPUT); pinMode(irgr, OUTPUT); analogWrite(irbs, irbr); pinMode(temp,INPUT_PULLUP); pinMode(vlvc, INPUT_PULLUP); pinMode(vlvo, INPUT_PULLUP); pinMode(butt, INPUT_PULLUP); pinMode(vopn, OUTPUT); digitalWrite(vopn,LOW); pinMode(vcpn, OUTPUT); digitalWrite(vcpn,LOW); //VirtualWire-------------------------------------------------------------------------------------------- ET.begin(details(mydata)); // Initialise the IO and ISR vw_set_rx_pin(receive_pin); vw_set_tx_pin(transmit_pin); //установка пина, к которому подключен data-вход передатчика vw_setup(500); // Скорость приёма vw_rx_start(); // Запуск режима приёма // Setting Up Device ID Serial.print("Getting Device ID... "); unique_device_id=EEPROMReadInt(0); if (unique_device_id != deviceID) { Serial.print("N/A, updating... "); //unique_device_id=random(10000, 60000); unique_device_id=deviceID; EEPROMWriteInt(0, unique_device_id); } Serial.println(unique_device_id); //----------------------------------------------------------------------------------------------------------- tone(buzz,3300,200); } void loop() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { // save the last time you blinked the LED previousMillis = currentMillis; statusSend(); } if(ET.receiveData()) // получили пакет данных, обрабатываем { if(mydata.destination_id == deviceID){ if(mydata.packet_id == packetID){ if(mydata.command == 10){ if(mydata.data == 1){ Serial.println("Radio Command Received to Open the Valve!"); openValve(); } } } } if(mydata.destination_id == deviceID){ if(mydata.packet_id == packetID){ if(mydata.command == 10){ if(mydata.data == 2){ Serial.println("Radio Command Received to Close the Valve!"); closeValve(); } } } } } if(digitalRead(vlvo)==LOW){ vstatus=1; digitalWrite(irgr, LOW); digitalWrite(irrd, HIGH); } if(digitalRead(vlvc)==LOW){ vstatus=0; digitalWrite(irgr, HIGH); digitalWrite(irrd, LOW); } if(vstatus==3){ alarmActive(); } //Buttons---------------------------------------------------- int s = analogRead(butt); if(s > 50 && s < 100) { openValve(); } if(s > 100 && s < 200) { closeValve(); } //---------------------------------------------------------- } void openValve(){ do{ digitalWrite(vopn,HIGH); digitalWrite(vcpn,LOW); if(digitalRead(vlvo)==LOW){ vstatus=1; digitalWrite(irgr, LOW); digitalWrite(irrd, HIGH); } }while (vstatus==0); digitalWrite(vopn,LOW); //stop actuator digitalWrite(vcpn,LOW); Serial.println("Valve is OPEN!"); mydata.device_id = unique_device_id; mydata.destination_id = destinationID; mydata.packet_id = 111; mydata.command = 10; //command 10 execution command mydata.data = 3; Serial.println("Transmitting packet \"Valve OPEN\""); ET.sendData(); // отправка данных Serial.println("DONE"); } void closeValve(){ do{ digitalWrite(vopn,LOW); digitalWrite(vcpn,HIGH); if(digitalRead(vlvc)==LOW){ vstatus=0; digitalWrite(irgr, HIGH); digitalWrite(irrd, LOW); } }while(vstatus==1); digitalWrite(vopn,LOW); //stop actuator digitalWrite(vcpn,LOW); Serial.println("Valve is CLOSE!"); mydata.device_id = unique_device_id; mydata.destination_id = destinationID; mydata.packet_id = 111; mydata.command = 10; //command 10 execution command mydata.data = 4; Serial.println("Transmitting packet \"Valve CLOSED\""); ET.sendData(); // отправка данных Serial.println("DONE"); } void stopValve(){ vstatus=3; digitalWrite(vopn,LOW); digitalWrite(vcpn,LOW); } void alarmActive(){ unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { // save the last time you blinked the LED previousMillis = currentMillis; if (ledState == 0) { ledState = 1; digitalWrite(irgr, LOW); digitalWrite(irrd, HIGH); } else { ledState = 0; digitalWrite(irgr, HIGH); digitalWrite(irrd, LOW); } } } void statusSend(){ float v = vcc.Read_Volts(); //int Volt = v*100; float p = vcc.Read_Perc(VccMin, VccMax); Serial.print("VCC: "); Serial.print(v); Serial.print(" V, "); Serial.print(p); Serial.println(" %"); /* for(int i=0;i<10;i++){ int MTemp = map(analogRead(temp),1023,0,0,1023); Temp =Temp + (float)MTemp/11.975; delay(10); } Temp = Temp/100; */ int MTemp = map(analogRead(temp),1023,0,0,1023); Temp = (float)MTemp/11; Serial.print("Temp: "); Serial.print(Temp); Serial.println("*C"); //delay(1000); if(vstatus==1){ Serial.println("Valve is OPEN"); } else { Serial.println("Valve is CLOSED"); } //delay(1000); Serial.println("Valve Switches: "); Serial.print("vlvc: "); Serial.println(digitalRead(vlvc)); Serial.print("vlvo: "); Serial.println(digitalRead(vlvo)); //delay(1000); mydata.device_id = unique_device_id; mydata.destination_id = destinationID; if(vstatus==0){ mydata.packet_id = 112; //112 valve is close } if(vstatus==1){ mydata.packet_id = 113; //113 valve is open } mydata.command = v*10; //command 11 Sensors Read mydata.data = Temp*100; Serial.println(mydata.command); Serial.println(mydata.data); ET.sendData(); // отправка данных } |
Скетч передатчика:
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 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 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
#include <VirtualWire.h> #include <EasyTransferVirtualWire.h> #include <EEPROM.h> #include <OneWire.h> OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary) const int transmit_pin = 12; const int receive_pin = 11; unsigned int unique_device_id = 0; //create object unsigned int count = 1; //create object const int destinationID = 10002; unsigned long previousMillis = 0; // will store last time LED was updated const long interval = 1000; const int deviceID = 10001; //Unique Device ID EasyTransferVirtualWire ET; char buf[120]; struct SEND_DATA_STRUCTURE{ //наша структура данны. она должна быть определена одинаково на приёмнике и передатчике //кроме того, размер структуры не должен превышать 26 байт (ограничение VirtualWire) unsigned int device_id; unsigned int destination_id; unsigned int packet_id; byte command; int data; }; //переменная с данными нашей структуры SEND_DATA_STRUCTURE mydata; //ниже пару функций для записи данных типа unsigned int в EEPROM void EEPROMWriteInt(int p_address, unsigned int p_value) { byte lowByte = ((p_value >> 0) & 0xFF); byte highByte = ((p_value >> 8) & 0xFF); EEPROM.write(p_address, lowByte); EEPROM.write(p_address + 1, highByte); } unsigned int EEPROMReadInt(int p_address) { byte lowByte = EEPROM.read(p_address); byte highByte = EEPROM.read(p_address + 1); return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00); } void setup() { //pinMode(led_pin, OUTPUT); pinMode(A2, INPUT_PULLUP); Serial.begin(57600); // Debugging only ET.begin(details(mydata)); // Initialise the IO and ISR vw_set_rx_pin(receive_pin); vw_set_tx_pin(transmit_pin); //установка пина, к которому подключен data-вход передатчика vw_setup(500); // Скорость приёма vw_rx_start(); // Запуск режима приёма // Setting Up Device ID Serial.print("Getting Device ID... "); unique_device_id=EEPROMReadInt(0); if (unique_device_id != deviceID) { Serial.print("N/A, updating... "); //unique_device_id=random(10000, 60000); unique_device_id=deviceID; EEPROMWriteInt(0, unique_device_id); } Serial.println(unique_device_id); tone(A0,3400,200); } void loop() { int k=analogRead(A2); if(k < 100){ openValve(); } if(k > 100 && k<700){ closeValve(); } if(ET.receiveData()) // получили пакет данных, обрабатываем { if(mydata.destination_id == deviceID) Serial.print("Device ID: "); Serial.print(mydata.device_id); { if(mydata.packet_id == 112){ Serial.print(" Valve is CLOSE! "); } if(mydata.packet_id == 113){ Serial.print(" Valve is OPEN! "); } if(mydata.command == 10) { if(mydata.data == 3) { Serial.println(" Valve is OPEN!"); tone(A0,3400,200); } if(mydata.data == 4) { Serial.println(" Valve is CLOSE!"); tone(A0,3400,200); } } if(mydata.command >= 11){ Serial.print(" Battery Voltage: "); float volt = (float)mydata.command/10; Serial.print(volt); Serial.print("V "); float temp = (float)mydata.data/100; Serial.print("Temperature: "); Serial.print(temp); Serial.println("*C "); } } /* Serial.print("Got: "); Serial.print("Device ID: "); Serial.print(mydata.device_id); Serial.print(" Destination ID: "); Serial.print(mydata.destination_id); Serial.print(" Packet ID: "); Serial.print(mydata.packet_id); Serial.print(" Command: "); Serial.print(mydata.command); Serial.print(" Data: "); Serial.print(mydata.data); Serial.println(); //tone(A0,3400,200); */ } } void openValve(){ mydata.device_id = unique_device_id; mydata.destination_id = destinationID; mydata.packet_id = 111; mydata.command = 10; mydata.data = 1; Serial.println("Transmitting packet \"OPEN\""); /* Serial.print(mydata.packet_id); Serial.print(" device id "); Serial.print(mydata.device_id); Serial.print(" data: "); Serial.print(mydata.data); Serial.print(" ... "); */ ET.sendData(); // отправка данных Serial.println("DONE"); } void closeValve(){ mydata.device_id = unique_device_id; mydata.destination_id = destinationID; mydata.packet_id = 111; mydata.command = 10; mydata.data = 2; Serial.println("Transmitting packet \"CLOSE\""); /* Serial.print(mydata.packet_id); Serial.print(" device id "); Serial.print(mydata.device_id); Serial.print(" data: "); Serial.print(mydata.data); Serial.print(" ... "); */ ET.sendData(); // отправка данных Serial.println("DONE"); } void dsTemp(){ byte i; byte present = 0; byte type_s; byte data[12]; byte addr[8]; float celsius, fahrenheit; if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.println(); ds.reset_search(); delay(250); return; } Serial.print("ROM ="); for( i = 0; i < 8; i++) { Serial.write(' '); Serial.print(addr[i], HEX); } if (OneWire::crc8(addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); return; } Serial.println(); // the first ROM byte indicates which chip switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); // or old DS1820 type_s = 1; break; case 0x28: Serial.println(" Chip = DS18B20"); type_s = 0; break; case 0x22: Serial.println(" Chip = DS1822"); type_s = 0; break; default: Serial.println("Device is not a DS18x20 family device."); return; } ds.reset(); ds.select(addr); ds.write(0x44, 1); // start conversion, with parasite power on at the end delay(1000); // maybe 750ms is enough, maybe not // we might do a ds.depower() here, but the reset will take care of it. present = ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad Serial.print(" Data = "); Serial.print(present, HEX); Serial.print(" "); for ( i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); Serial.print(data[i], HEX); Serial.print(" "); } Serial.print(" CRC="); Serial.print(OneWire::crc8(data, 8), HEX); Serial.println(); // Convert the data to actual temperature // because the result is a 16 bit signed integer, it should // be stored to an "int16_t" type, which is always 16 bits // even when compiled on a 32 bit processor. int16_t raw = (data[1] << 8) | data[0]; if (type_s) { raw = raw << 3; // 9 bit resolution default if (data[7] == 0x10) { // "count remain" gives full 12 bit resolution raw = (raw & 0xFFF0) + 12 - data[6]; } } else { byte cfg = (data[4] & 0x60); // at lower res, the low bits are undefined, so let's zero them if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms //// default is 12 bit resolution, 750 ms conversion time } celsius = (float)raw / 16.0; fahrenheit = celsius * 1.8 + 32.0; Serial.print(" Temperature = "); Serial.print(celsius); Serial.print(" Celsius, "); Serial.print(fahrenheit); Serial.println(" Fahrenheit"); } |
Скетчи не финальные и будут обновляться. В дальнейшем планирую повесить на устройства фичу ретранслятора, как на устройствах стандарта Z-Wave…
работа устройства:
Теперь попробуем все это впихнуть попавшуюся под руку коробку внешнего монтажа. Клеится все на двусторонней скотч.
впихиваем попавшуюся под руку литий-ионную батарею:
Далее нам нужен 5и жильный кабель для удлинения кабеля серво-вентиля и какая нибудь розетка, что бы было удобнее отсоединять ее от блока управления если что. Идеально подойдет любой USB шнур, он как раз 5и жильный (экран, плюсовой провод, минус и две жилы на данные) но надо быть уверенным, что кабель добротный, не использовать разный хлам-китай (есть и НЕ хлам-китай) плюс ко всему прозвонить тестером, что бы экран не соединялся к минусовому проводу, часто для экономии они не 5и, а 4х жильные, но даже если так, то он подойдет, только надо будет сделать кое какую модификацию внутри сервопривода – развести два концевых выключателя через сопротивление.
концевые выключатели – именно они посылают сигнал, когда вентиль открыт и закрыт!
Видео получившегося:
Немного фоток: установка мембранной клавиатуры с последующей разводкой через сопротивления к всего лишь одному цифровому порту (экономим на чем можем 😉 )
И монтаж устройства непосредственно на место:
Тестирование устройства:
Ну вот и все! Надеюсь статья вам понравится и будет полезной.
Продолжение следует…