Все мы знакомы со счетчиками электроэнергии, которые установлены сейчас в каждой квартире или домохозяйстве. Обычно мы смотрим их показания один раз в месяц когда заполняем квитанции на оплату коммунальных услуг. Но иногда количество потребленной электроэнергии становится для нас неожиданностью – мы обнаруживаем что потребили ее очень много. Поэтому в данной статье мы рассмотрим проект умного измерителя электроэнергии на ESP12 и Arduino, который будет информировать нас по SMS/E-mail когда количество потребленной энергии будет достигать определенного значения (границы). Данный проект относится к так называемой концепции интернета вещей (IoT – Internet of Things).
Рассматриваемый в данном проекте измеритель электроэнергии будет не только передавать вам SMS/Email при наступлении определенных ситуаций, но также с его помощью вы можете контролировать потребление электроэнергии из любой точки земного шара (где есть интернет). Для измерения электроэнергии мы будем использовать датчик тока ACS712.
Для передачи информации по WiFi мы будем использовать модуль ESP8266, а контроль потребления электроэнергии будем осуществлять с помощью приложения для Android.
Необходимые компоненты
- Плата Arduino Uno (купить на AliExpress).
- ESP12/NodeMCU (устройство управления многосторонней связью) (купить на AliExpress).
- ACS712-30Amp Current sensor (датчик тока) (купить на AliExpress).
- Любой потребитель электроэнергии переменного тока.
- Male-Female Wires (соединительные провода папа-мама).
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Принцип работы датчика тока ACS712
Прежде чем приступить к рассмотрению проекта остановимся кратко на принципах работы датчика тока ACS712 поскольку он является ключевым элементом нашего проекта. Измерение силы тока, а особенно силы переменного тока, всегда является достаточно сложной задачей вследствие наличия большого количества шумов, вызванных проблемами с изоляцией и т.д. Но с использованием датчика тока ACS712 эта задача значительно упрощается.
Этот датчик построен на использовании эффекта Холла, открытым ученым Эдвином Холлом. В соответствии с данным эффектом когда проводник с током помещается в магнитное поле на его концах формируется напряжение, перпендикулярное направлению протекания тока и направлению действующего магнитного поля. Измерять это напряжение мы будем в милливольтах и будем называть его напряжением Холла. Величина этого напряжения будет пропорциональна величине протекающего через проводник тока.
Основным достоинством датчика тока ACS712 является то, что он может измерять как переменный (AC), так и постоянный ток (DC) и он также обеспечивает изоляцию между нагрузкой и измерительным устройством (в нашем случае это будет плата Arduino. Как показано на следующем рисунке, датчик тока ACS712 имеет три контакта – Vcc (питающее напряжение), Vout (выход) и Ground (земля).
Слева на рисунке показаны два контакта, которые подсоединяются к тому месту, где необходимо измерить ток. Датчик работает от напряжения +5V – его необходимо подать на контакт Vcc датчика. Контакт Ground датчика необходимо подсоединить к земле схемы. Если сила измеряемого тока равна нулю, то на выходном контакте датчика напряжение равно 2500mV, если протекающий ток положителен, то напряжение на выходе датчика будет больше 2500mV, если отрицателен – то меньше 2500mV.
Для считывания напряжения с этого контакта мы будем использовать один из аналоговых входов Arduino – на выходе его АЦП (аналогово-цифровой преобразователь) будет значение 512 когда на входе контакта будет напряжение 2500mV – то есть когда ток не протекает. Это значение будет уменьшаться когда ток будет протекать в обратном (отрицательном) направлении, и увеличиваться когда ток будет протекать в прямом (положительном) направлении. В следующей таблице представлены примеры значений на выходе АЦП аналогового контакта Arduino в зависимости от величины протекающего через датчик тока.
Эти значения были рассчитаны на основе даташита на датчик ACS712. Вы их также можете рассчитать по следующим формулам:
Vout Voltage(mV) = (ADC Value/ 1023)*5000
Ток через проводник (A) = (Vout(mv)-2500)/185
Работа схемы
Схема измерителя электроэнергии на основе ESP12 и Arduino представлена на следующем рисунке.
Для модуля ESP12/NodeMCU необходимо сделать следующие соединения:
- подсоединить контакт Rx ESP12 к контакту Tx платы Arduino;
- подсоединить контакт Tx ESP12 к контакту Rx платы Arduino.
У NodeMCU (ESP12) нет аналоговых контактов, поэтому для связи с данным модулем мы использовали порт последовательной связи. Но данный модуль работает с напряжениями 3.3 Вольта, поэтому чтобы не повредить его напряжением 5 В с контактов Arduino мы использовали делитель напряжения.
Выходной контакт датчика тока в схеме подключен к аналоговому контакту A0 платы Arduino.
Внешний вид собранной схемы показан на следующем рисунке.
Чтобы осуществлять контроль расходования электроэнергии через интернет мы использовали MQTT брокера, реализованного на платформе AdaFruit IO. Для этого необходимо выполнить следующие действия:
- Зарегистрировать себе аккаунт на AdaFruit для хранения и считывания данных потребления электроэнергии.
- Создать Applet (прикладную программу) в сервисе IFTTT для формирования сообщений при помощи SMS/Email.
- Написать коды программ для Arduino и ESP12 Wi-Fi модуля.
Более подробно все эти процессы описаны далее в статье.
Регистрация аккаунта в AdaFruit
Здесь вам необходимо выполнить следующие шаги:
Шаг 1. Зарегистрировать аккаунт на Adafruit IO или войти в свой аккаунт если вы там уже зарегистрированы.
Шаг 2. Кликните на My account -> Dashboard.
Шаг 3. Кликните на Actions и создайте новую приборную доску (Dashboard).
Шаг 4. Введите имя и название для вашего проекта и нажмите Create (создать).
Шаг 5. Нажмите на Key button (кнопка с изображением ключа – см. рисунок) и запишите ключи, которые предоставит вам этот сервис (см. рисунок). Далее эти ключи будут использоваться в коде программы.
Шаг 6. Кликните на кнопку ‘+’ чтобы создать новый блок и кликните на Gauge (масштаб) чтобы отобразить уровень расходования электроэнергии. Вы можете использовать простое текстовое поле для отображения этой информации.
Шаг 7. Далее введите имя фида (Name of Feed) и нажмите на Create (создать). Затем выберите фид и кликните на Next step (следующий шаг).
Шаг 8. В настройках блока (block settings) введите минимальное (в нашем случае 0) и максимальное значения (в нашем случае 100). В дальнейшем вы можете изменить эти введенные значения.
Шаг 9. Ваш вид для учета электроэнергии (Power feed) успешно создан. Теперь создайте фид для отображения счёта (Bill), нажав на кнопку “+”.
После этого вам необходимо будет установить соединение с AdaFruit IO чтобы передавать SMS/E-mail с использованием сервиса IFTTT.
Создание прикладной программы в IFTTT для передачи SMS/Email
Шаг 1. Зарегистрируйтесь в сервисе IFTTT или войдите туда если у вас уже есть там аккаунт.
Шаг 2. На вкладке My Applets (мои прикладные программы) кликните на New Applet (новая прикладная программа).
Шаг 3. Кликните на +this.
Шаг 4. Найдите AdaFruit и кликните на нее.
Шаг 5. Кликните на "Monitor a feed on AdaFruit IO" (мониторить фид в AdaFruit IO).
Шаг 6. Выберите счет (bill) в качестве фида (Feed), взаимоотношение (Relationship) выберите ‘equal to’ (равно) и введите границу (мы ввели 4) при достижении которой вам будет высылаться уведомление на E-mail. Кликните на Create action (создать действие).
Шаг 7. Кликните на +that. В поиске введите G-mail, кликните потом на ней и залогиньтесь со своими данными в g-mail.
Шаг 8. Кликните на send yourself an email (передать самому себе email).
Шаг 9. Запишите свой subject (тему) и ее описание (body) как показано на рисунке и кликните на create.
Шаг 10. Ваше уведомление создано. Посмотрите его и нажмите на finish (завершить).
С интеграцией нашего проекта в сеть интернет мы закончили, теперь можно переходить к написанию кода программы.
Объяснение кода программы
В нашем проекте мы используем последовательную связь между ESP12 и Arduino. Поэтому нам необходимо написать программу и для Arduino, и для ESP12 (NodeMCU).
Объяснение кода программы для передающей части (для Arduino Uno)
Полный код программы приведен в конце статьи, здесь же мы рассмотрим его наиболее важные фрагменты. В программе мы будем использовать специальную библиотеку для работы с датчиком тока, которую можно скачать по следующей ссылке. В этой библиотеке используются специальные функции для расчета силы тока. Конечно, эти функции вы можете запрограммировать и самостоятельно, но в данной библиотеке используются специальные алгоритмы для точного расчета силы тока, поэтому целесообразнее использовать все таки ее.
Первым делом в программе необходимо подключить данную библиотеку.
1 |
#include "ACS712.h" |
Создадим массив чтобы хранить в нем значения мощности, которые затем будут передаваться в NodeMCU.
1 |
char watt[5]; |
Сообщим Arduino Uno, что к ее контакту A0 будет подключен датчик тока ACS712-30Amp (на 30 Ампер). Измените соответствующим образом первый аргумент в следующей команде если вы будете использовать вариант датчика тока на 20 или 5 Ампер.
1 |
ACS712 sensor(ACS712_30A, A0); |
Далее, в функции setup установим скорость последовательной связи равную 115200 бод/с для обмена данными с NodeMCU. Вызовем функцию sensor.calibrate() для калибровки датчика тока (чтобы в дальнейшем считывать с него правильные значения).
1 2 3 4 |
void setup() { Serial.begin(115200); sensor.calibrate(); } |
В функции loop вызовем функцию sensor.getCurrentAC() чтобы считать текущее значение тока и сохранить его в переменной I. После получения значения тока рассчитаем мощность по стандартной формуле P=V*I. В качестве значения напряжения мы использовали 230V – измените это значение если в вашей сети другое значение напряжения.
1 2 3 4 |
void loop() { float V= 230; float I = sensor.getCurrentAC(); float P = V * I; |
Следующие три строчки кода конвертируют значение мощности в ватт-часы (Wh) – то есть значение мощности умножается на время работы.
1 2 3 |
last_time = current_time; current_time = millis(); Wh = Wh+ P *(( current_time -last_time) /3600000.0) ; |
Затем нам необходимо конвертировать эти ватт-часы в символьный массив чтобы их можно было передать на NodeMCU – для этой цели мы будем использовать функцию dtostrf().
1 |
dtostrf(Wh, 4, 2, watt); |
Формат этой функции выглядит следующим образом:
1 |
dtostrf(floatvar, StringLengthIncDecimalPoint, numVarsAfterDecimal, charbuf); |
Далее этот массив символьных данных передадим в буфер последовательной связи с помощью функции Serial.write() – то есть осуществим передачу значений ватт-часов в NodeMCU.
1 2 3 |
Serial.write(watt); delay(10000); } |
Объяснение кода программы для приемной части (для NodeMCU ESP12)
Для написания данной программы нам понадобится библиотека AdaFruit MQTT library, которую можно скачать по этой ссылке.
После этого откройте Arduino IDE. В ней откройте examples -> AdaFruit MQTT library -> mqtt_esp8266.
Нам необходимо будет изменить этот код в соответствии с ключами, полученными ранее в сервисе Adafruit IO (AIO keys), вашими настройками для Wi-Fi и поступающими по последовательному порту связи данными от платы Arduino. Первым делом в программе нам необходимо подключить библиотеки для работы с Wi-Fi модулем ESP12 и для работы с AdaFruit MQTT.
1 2 3 |
#include <ESP8266WiFi.h> #include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" |
Инициализируем SSID и пароль (Password) для Wi-Fi, к которому мы будем подключать наш модуль ESp-12e.
1 2 |
#define WLAN_SSID "xxxxxxxx" #define WLAN_PASS "xxxxxxxxxxx" |
Далее инициализируем сервер AdaFruit и порт сервера на “io.adafruit.com” – для него зафиксировано значение "1883".
1 2 |
#define AIO_SERVER "io.adafruit.com" #define AIO_SERVERPORT 1883 |
В следующих командах вам необходимо заменить имя пользователя (username) и ключи с сервиса Adafruit IO (AIO keys) на ваши значения.
1 2 |
#define AIO_USERNAME "********" #define AIO_KEY "******************************" |
Затем мы создадим класс для ESP12 с именем WiFiClient чтобы с его помощью затем коннектиться к серверу MQTT.
1 |
WiFiClient client; |
Установка класса клиента для MQTT осуществляется с помощью команды следующего формата:
1 |
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY); |
Необходимо установить фиды с именами 'Power' и ‘bill’ для публикации изменений в них.
1 2 |
Adafruit_MQTT_Publish Power = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Power"); Adafruit_MQTT_Publish bill = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/bill"); |
В функции setup мы будем подключать Wi-Fi модуль к точке доступа Wi-fi.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void setup() { Serial.begin(115200); delay(10); Serial.println(F("Adafruit MQTT demo")); // Connect to WiFi access point. Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(WLAN_SSID); WiFi.begin(WLAN_SSID, WLAN_PASS); …. …. … } |
В функции loop мы будем проверять поступающие данные от платы Arduino и публиковать эти данные в AdaFruit IO.
1 2 3 4 5 6 7 8 |
void loop() { //необходимо удостовериться в том, что соединение с сервером MQTT "живо" // то есть мы делаем первое соединение и автоматический реконнект при пропадании соединения //более подробно это можно посмотреть в функции MQTT_connect(); MQTT_connect(); int i=0; float watt1; |
В этой функции осуществляется проверка поступающих данных от Arduino и сохранение этих данных в массив watt[] с помощью использования функции serial.read().
1 2 3 4 5 6 7 |
if(Serial.available() > 0 ){ delay(100); //эта задержка необходима для того, чтобы все переданные по последовательному порту данные были приняты вместе while(Serial.available() && i<5) { watt[i++] = Serial.read(); } watt[i++]='\0'; } |
С помощью функции atof() осуществляется конвертирование принятых символов в значение вещественного типа, которое сохраняется в переменной watt1.
1 |
watt1 = atof(watt); |
Затем мы осуществляем расчет счета за потребленную электроэнергию при помощи умножения значения потребленной энергии (в ватт-часах) на значение тарифа за электричество. На 1000 в следующей команде мы делим для того, чтобы перевести ватт-часы в киловатт-часы (потому что обычно тариф за электроэнергию указывается для потребленных кВт/ч).
1 |
bill_amount = watt1 * (energyTariff/1000); // 1unit = 1kwH |
Затем мы можем начинать передачу в интернет полученных значений.
1 2 3 |
Serial.print(F("\nSending Power val ")); Serial.println(watt1); Serial.print("..."); |
В следующем фрагменте кода осуществляется публикация полученных значений мощности в соответствующем фиде.
1 2 3 4 5 |
if (! Power.publish(watt1)) { Serial.println(F("Failed")); } else { Serial.println(F("OK!")); } |
Далее осуществляется публикация счета за электричество.
1 2 3 4 5 |
if (! bill.publish(bill_amount)) { Serial.println(F("Failed")); } else { Serial.println(F("OK!")); } |
Наше значение счета за электричество может изменяться достаточно быстро (при включении и выключении новых потребителей электроэнергии), однако сервису IFTTT необходимо некоторое время для того чтобы исполнить написанный нами ранее applet (прикладную программу), поэтому в программе предусмотрена задержка чтобы не перегружать сервис IFTTT слишком частыми запросами. Вы можете изменить границу, при превышении которой вам будет высылаться email, также вы может изменить и другие настройки в IFTTT AdaFruit IO setup.
1 2 3 4 5 6 7 8 |
if (bill_amount==4){ for (int i =0; i<=2; i++) { bill.publish(bill_amount); delay(5000); } bill_amount =6; } |
Полный код программы для Arduino и NodeMCU ESP12 приведен в конце данной статьи.
Загрузите коды этих программ в эти устройства. Соедините все элементы проекта как показано в приведенной ранее схеме и откройте сайт io.adafruit.com. Откройте приборную доску (dashboard), которую вы там создали. После этого вы сможете наблюдать как в ней будут меняться значения потребления электроэнергии и счета за электричество.
Когда ваш счет достигнет значения 4 (вы можете изменить это значение на нужное вам) вы получите email примерно следующего вида:
Приложение для Android для контроля потребления электроэнергии
Вы можете использовать приложение для Android для контроля описанных значений потребления электроэнергии и счета за электричество. Для этого скачайте MQTT Dashboard android app из Play store.
Чтобы осуществить в нем соединение с io.adafruit.com выполните следующую последовательность шагов.
Шаг 1. Откройте приложение и кликните в нем на знак “+”. Напишите в поле Client Id любое значение которое захотите. Сервер и порт оставьте такими как показано на следующем рисунке.
Вы можете получить имя пользователя (Username) и пароль (Active key) с приборной доски AdaFruit IO как показано на следующем рисунке.
Шаг 2. Выберите Electricity Meter (измеритель электричества) и выберите Subscribe (подписаться). Для подписки укажите дружественное (сетевое) имя (friendly name) и тему (topic) в формате ‘yourusername’/feeds/’feedname’, затем нажмите create (создать).
![]() |
![]() |
Шаг 3. Аналогичным образом сделайте подписку на значение счета за электричество (bill feed).
Шаг 4. После того как ваши устройства начнут потреблять электроэнергию значения потребляемой мощности и счета за электричество будут отображаться в приложении.
Таким образом, мы сконструировали умный измеритель электроэнергии, благодаря которому мы можем контролировать потребление электроэнергии из любой точки земного шара (где есть интернет). Также на нашем сайте вы можете посмотреть и другие проекты, относящиеся к категории интернета вещей.
Исходный код программы
Код программы для Arduino
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include "ACS712.h" char watt[5]; ACS712 sensor(ACS712_30A, A0); unsigned long last_time =0; unsigned long current_time =0; float Wh =0 ; void setup() { Serial.begin(115200); sensor.calibrate(); } void loop() { float V = 230; float I = sensor.getCurrentAC(); // Serial.println(I); float P = V * I; last_time = current_time; current_time = millis(); Wh = Wh+ P *(( current_time -last_time) /3600000.0) ; dtostrf(Wh, 4, 2, watt); Serial.write(watt); delay(10000); } |
Код программы для NodeMCU ESP12
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 |
#include <ESP8266WiFi.h> #include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" #define WLAN_SSID "a*************" #define WLAN_PASS "*******************" char watt[5]; #define AIO_SERVER "io.adafruit.com" #define AIO_SERVERPORT 1883 #define AIO_USERNAME "rjrishabh" #define AIO_KEY "***********************" WiFiClient client; int bill_amount = 0; unsigned int energyTariff = 8.0; Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY); Adafruit_MQTT_Publish Power = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Power"); Adafruit_MQTT_Publish bill = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/bill"); void MQTT_connect(); void setup() { Serial.begin(115200); delay(10); Serial.println(F("Adafruit MQTT demo")); // соединение с точкой доступа WiFi Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(WLAN_SSID); WiFi.begin(WLAN_SSID, WLAN_PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void loop() { // Ensure the connection to the MQTT server is alive (this will make the first // connection and automatically reconnect when disconnected). See the MQTT_connect // function definition further below. MQTT_connect(); int i=0; float watt1; if(Serial.available() > 0 ){ delay(100); //allows all serial sent to be received together while(Serial.available() && i<5) { watt[i++] = Serial.read(); } watt[i++]='\0'; } watt1 = atof(watt); bill_amount = watt1 * (energyTariff/1000); // 1unit = 1kwH Serial.print(F("\nSending Power val ")); Serial.println(watt1); Serial.print("..."); if (! Power.publish(watt1)) { Serial.println(F("Failed")); } else { Serial.println(F("OK!")); } if (! bill.publish(bill_amount)) { Serial.println(F("Failed")); } else { Serial.println(F("OK!")); } if (bill_amount==4){ for (int i =0; i<=2; i++) { bill.publish(bill_amount); delay(5000); } bill_amount =6; } delay(5000); } // функция для соединения и повторного соединения (при разрыве) с MQTT сервером // Should be called in the loop function and it will take care if connecting. void MQTT_connect() { int8_t ret; // стоп если уже подсоедине if (mqtt.connected()) { return; } Serial.print("Connecting to MQTT... "); uint8_t retries = 3; while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected Serial.println(mqtt.connectErrorString(ret)); Serial.println("Retrying MQTT connection in 5 seconds..."); mqtt.disconnect(); delay(5000); // wait 5 seconds retries--; if (retries == 0) { // basically die and wait for WDT to reset me while (1); } } Serial.println("MQTT Connected!"); } |