Измерители электроэнергии (электросчетчики) достаточно широко распространены в современном мире – их можно найти везде, где есть потребители электроэнергии. Разумеется, они производятся современных промышленностью в достаточных объемах и их можно сравнительно легко купить в магазинах. Но иногда возможности, предоставляемые электросчетчиками промышленного изготовления, не полностью удовлетворяют потенциального потребителя – например, невозможность удаленно посмотреть потребление энергии, а во многих ситуациях это достаточно востребованная задача.
Поэтому в данной статье мы рассмотрим создание собственного (своими руками, DIY) умного измерителя электроэнергии (Energy Monitor) на основе платы Raspberry Pi, показания которого можно будет смотреть из любой точки Земли где есть сеть интернет. Для реализации подобной глобальной доступности показаний измерителя электроэнергии мы будем использовать платформу Adafruit.io, занимающую одну из лидирующих позиций при создании различных проектов из категории интернета вещей (Internet of Things, IoT).
Также на нашем сайте вы можете посмотреть проект умного измерителя электроэнергии на основе платы Arduino. Также, если вас интересует тематика создания простейших ваттметров на основе микроконтроллеров, то рекомендуем ознакомиться с проектом создания простейшего ваттметра на основе платы Arduino – эта статья стала достаточно популярной в сети.
Предупреждение: данный проект включает в себя работу с напряжением переменного тока (в сети), которое может быть опасно для жизни и здоровья человека. Примите соответствующие меры предосторожности прежде чем начинать работу с данным проектом.
Структурная схема работы проекта
Структурная схема работы нашего умного измерителя электроэнергии на основе платы Raspberry Pi показана на следующем рисунке.
Назначение элементов этой схемы.
Current Sensing Unit (блок измерения тока): построен на основе датчика измерения тока SCT-013 и способен измерять ток до 100A (в зависимости от версии датчика). Датчик преобразует проходящий через него ток в ток небольшой величины, который затем подается на аналого-цифровой преобразователь (АЦП, в англ. ADC) через сеть делителей напряжения.
Voltage Sensing Unit (блок измерения напряжения): поскольку автор данной статьи не смог найти в продаже подходящий подобный блок, то он сконструировал самодельный (DIY) безтрансформаторный датчик напряжения, принцип действия которого основан на использовании делителя напряжения. Полученное с выхода данного делителя напряжение подается на вход АЦП.
Processing Unit (блок обработки): включает в себя АЦП и плату Raspberry Pi. АЦП преобразует поступающие аналоговые сигналы в цифровую форму и подает их на Raspberry P, которая на их основе рассчитывает потребляемое значение электроэнергии и затем передает это значение в облачный сервис (облако) платформы Adafruit.io
Необходимые компоненты
- Плата Raspberry Pi 3 или 4 (можно использовать и RPI2, но тогда для нее потребуется WiFi адаптер) (купить на AliExpress).
- ADS1115 16bit I2C ADC (16-битный АЦП, работающий по интерфейсу I2C) (купить на AliExpress).
- YHDC SCT-013-000 (датчик тока) (купить на AliExpress).
- Резистор 10 кОм 2 Вт (купить на AliExpress).
- Резистор 3,3 кОм 2 Вт.
- Резистор 10 кОм 0,5 Вт – 2 шт. (купить на AliExpress).
- Резистор 33 Ом (купить на AliExpress).
- Диод 1N4007 – 4 шт. (купить на AliExpress).
- 3.6v Zener Diode (стабилитрон).
- Потенциометр 10 кОм (купить на AliExpress).
- Конденсатор 1 мкФ 50 В (купить на AliExpress).
- Конденсатор 10 мкФ 50 В – 2 шт. (купить на AliExpress).
- Адаптер питания 2.5A 5V MicroUSB.
- Макетная плата.
- Соединительные провода.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Этот проект сможет работать практически на любой операционной системе для Raspberry Pi. Автор данного проекта использовал Raspberry Pi buster OS, установленную на Pi 3 (также будет работать и на Pi 4) и осуществлял доступ к ней по протоколу SSH, но вы можете использовать любой другой удобный для себя способ взаимодействия с платой Raspberry Pi.
Подготовка платы Raspberry Pi
Для подготовки платы Raspberry Pi к работе в составе данного проекта с ней необходимо произвести дополнительные действия, которые мы рассмотрим далее.
Включение интерфейса I2C
Поскольку плата Raspberry Pi не содержит в своем составе встроенного АЦП, то в данном проекте мы вынуждены использовать внешний 16-битный модуль АЦП ADS1115, который будет передавать информацию плате Raspberry Pi по интерфейсу I2C, поэтому нам необходимо включить использование данного интерфейса в плате. Для этого запустите панель настроек платы. Это можно сделать или с помощью команды sudo raspi-config, или с помощью графического меню как в нашем случае.
В открывшейся панели настроек включите использование интерфейса I2C. После этого перезагрузите плату Raspberry Pi чтобы изменения вступили в силу.
Установка библиотеки ADS11xx от Adafruit
Следующим шагом мы установим библиотеку ADS11xx от Adafruit, которая значительно упростит нам работу с модулем АЦП. Для ее установки выполните следующую последовательность шагов:
- Установите последние обновления на вашу плату Raspberry Pi с помощью команд: sudo apt-get update, sudo apt-get upgrade.
- Выполните команду cd ~ чтобы убедиться что вы находитесь в домашнем каталоге.
- Установите необходимые пакеты с помощью команд: sudo apt-get install build-essential python-dev python-smbus git.
- Клонируйте каталог с библиотекой ADS от Adafruit с помощью команды git clone https://github.com/adafruit/Adafruit_Python_ADS1x15.git.
- Водите в каталог с клонированной библиотекой и запустите ее установщик с помощью команд: cd Adafruit_Python_ADS1x1z, sudo python setup.py install.
На этом установка библиотеки будет закончена. Вы можете проверить работу библиотеки, собрав схему проекта (представленную ниже) и запустив на выполнение пример кода программы, который поставляется вместе с библиотекой. Для этого необходимо изменить каталог, в котором вы находитесь: cd examples и затем запустить на выполнение пример тестовой программы с помощью команды python simpletest.py.
Установка модуля Python от Adafruit.IO
В проекте нашего умного измерителя электроэнергии мы будем передавать измеренные значения потребленной электроэнергии в облако Adafruit IO, в котором эти данные можно просмотреть из любой точки Земли где есть подключение к сети интернет. Либо же эти данные потом можно передавать в платформу IFTTT чтобы с ее помощью выполнять какие либо действия, основанные на измеренных значениях электроэнергии (например, можно отправлять себе SMS когда потребление энергии станет выше определенного порога).
Модуль Python от Adafruit.IO содержит подпрограммы и функции, которые помогут передавать нам наши данные (стримить) в облако. Для установки данного модуля выполните следующую последовательность действий:
- Выполните команду cd ~ чтобы вернуться в домашний каталог.
- Далее выполните команду sudo pip3 install adafruit-io. В результате выполнения данной команды должен установиться модуль Python от Adafruit.IO.
Регистрация аккаунта Adafruit.io
Для того, чтобы иметь возможность работать с платформой Adafruit IO нам необходимо зарегистрировать в ней свой аккаунт. Нам будут необходимы имя пользователя (username) и ключ доступа (AIO key) к этой платформе чтобы передавать туда наши данные. Для регистрации себе там аккаунта зайдите на https://io.adafruit.com/, там нажмите кнопку "get started for free" (зарегистрируйтесь бесплатно) и заполните необходимые параметры. Когда процесс регистрации будет завершен вы увидите кнопку View AIO Key в правом верхнем углу экрана.
Нажмите на нее чтобы получить свой ключ доступа (AIO key).
Скопируйте этот ключ в надежное место. Чтобы упростить процесс передачи наших данных в облачный сервис можно создать фиды (feeds), в которые будут передаваться данные. Мы будем передавать данные энергопотребления, поэтому создадим соответствующий фид. Для создания фида нажмите на “feeds” вверху страницы и затем нажмите на add new feed (добавить новый фид).
Вы можете назвать фид как угодно – мы его назвали energy consumption. Можно также создать фиды еще для значений тока и напряжения – тогда можно будет передавать данные и в них, внеся соответствующие изменения в программу.
Схема проекта
Схема нашего проекта немного сложновата для начинающих и предусматривает подключение к сети переменного тока, что влечет за собой опасность для жизни и здоровья человека. Поэтому примите соответствующие меры предосторожности прежде чем подключать схему данного проекта к сети переменного тока. Если вы не уверены в своих навыках работы с сетью переменного тока, лучше этот проект собирать под руководством опытного наставника.
Схема проекта предусматривает соединение датчиков тока и напряжения с АЦП, который, в свою очередь, будет передавать данные плате Raspberry Pi. Для удобства всю схему мы разбили на ее структурные компоненты.
Схема блока измерения тока
Показана на следующем рисунке.
Внешний вид трансформатора (датчика) тока, использованного в данной схеме, показан на следующем рисунке. Как видите, он имеет три вывода: ground, Cout и 3.3V.
Схема блока измерения напряжения
Показана на следующем рисунке.
Схема блока вычислений
Соедините выше рассмотренные схемы блоков измерения тока и напряжения с модулем АЦП ADS1115, выход которого подключен к плате Raspberry Pi. Выходы блоков измерения тока и напряжения подключены к контактам A0 и A1 модуля ADS1115 соответственно.
Убедитесь в том, что земля (GND) блоков измерения тока и напряжения подключена к земле (GND) модуля АЦП или платы Raspberry Pi.
Чтобы сделать конструкцию проекта более устойчивой мы закрепили датчики напряжения и тока на Protoboard (двухсторонняя макетная плата для монтажа SMD компонентов). Помните о том, что не рекомендуется выполнять сборку цепей переменного тока на макетной плате.
После сборки аппаратной части проекта у нас получилась конструкция следующего вида.
Объяснение программы для Raspberry Pi
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Для написания программы проекта мы использовали Python 3. Помните о том, что некоторые функции python 3 могут не работать в python 2.7. Поэтому, если вы хотите использовать python 2.7, то вам необходимо будет внести некоторые изменения в программу.
Алгоритм работы программы очень прост. Мы по протоколу I2C будем считывать в плату Raspberry Pi с модуля АЦП ADS1115 значения тока и напряжения. Считываемые аналоговые значения тока и напряжения дискретизируются и из них извлекается квадратный корень (чтобы получить среднеквадратичные значения этих величин). Затем рассчитывается потребляемая мощность в кВт и ее значения передаются в фид Adafruit IO через определенные промежутки времени.
Первым делом в программе нам необходимо подключить (импортировать) используемые библиотеки. Часть из них встроенные в язык программирования (time и math), а другую часть библиотек мы установили ранее в данном проекте.
1 2 3 4 |
import time import Adafruit_ADS1x15 from Adafruit_IO import * import math |
Далее мы создадим объект для работы с модулем АЦП.
1 2 |
# Create an ADS1115 ADC (16-bit) instance.. adc1 = Adafruit_ADS1x15.ADS1115() |
Затем в программе нам необходимо ввести имя пользователя (username) и ключ доступа (“AIO” key), которые мы ранее получили в сервисе adafruit IO.
1 2 3 |
username = ‘enter your username in between this quotes’ AIO_KEY = 'your aio key' aio = Client(username, AIO_KEY) |
Храните этот ключ в надежном месте – он может быть использован злоумышленниками для доступа к вашему аккаунту на adafruit io без вашего разрешения.
Далее в программе мы объявим ряд необходимых нам переменных – для хранения коэффициента усиления АЦП (gain for the ADC), числа отсчетов (the number of samples) и округление (которое не очень критично).
1 2 3 |
GAIN = 1 # see ads1015/1115 documentation for potential values. samples = 200 # number of samples taken from ads1115 places = int(2) # set rounding |
Затем мы создадим бесконечный цикл while в котором будем мониторить поступающие значения тока и напряжения и передавать рассчитанные значения мощности в сервис Adafruit io через определенные интервалы времени. Цикл начнется с присваивания нуля всем используемым в нем переменным.
1 2 3 4 5 6 7 8 9 10 11 12 |
while True: # reset variables count = int(0) datai = [] datav = [] maxIValue = 0 #max current value within sample maxVValue = 0 #max voltage value within sample IrmsA0 = 0 #root mean square current VrmsA1 = 0 # root mean square voltage ampsA0 = 0 #current peak voltsA1 =0 #voltage kilowatts = float(0) |
Поскольку мы работаем с цепями переменного тока, то на выходе датчика SCT-013 и датчика напряжения (в нашем случае самодельного) будет синусоидальный сигнал. Чтобы определить значения тока и напряжения синусоидального сигнала, нам необходимо узнать пиковые значения этих сигналов. Чтобы определить пиковые значения мы будем дискретизировать значения этих сигналов с помощью взятия 200 отсчетов каждого из этих сигналов и среди этих 200 отсчетов будем находить максимальное значение, которое и будет пиковым.
1 2 3 4 5 6 7 8 9 |
for count in range(samples): datai.insert(count, (abs(adc1.read_adc(0, gain=GAIN)))) datav.insert(count, (abs(adc1.read_adc(1, gain=GAIN)))) # see if you have a new maxValue print (datai[count]) if datai[count] > maxIValue: maxIValue = datai[count] if datav[count] > maxVValue: maxVValue = datav[count] |
Далее мы конвертируем значения с АЦП в реальные значения напряжения и затем вычислим их среднеквадратические значения, то есть найдем значения RMS (Root Mean Square) напряжения и тока.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#calculate current using the sampled data # the sct-013 being used is calibrated for 1000mV output @ 30A. IrmsA0 = float(maxIValue / float(2047) * 30) IrmsA0 = round(IrmsA0, places) ampsA0 = IrmsA0 / math.sqrt(2) ampsA0 = round(ampsA0, places) # Calculate voltage VrmsA1 = float(maxVValue * 1100/ float(2047)) VrmsA1 = round(VrmsA1, places) voltsA1 = VrmsA1 / math.sqrt(2) voltsA1 = round(voltsA1, places) print('Voltage: {0}'.format(voltsA1)) print('Current: {0}'.format(ampsA0)) |
После этого рассчитаем значение мощности и передадим его в сервис adafruit.io.
1 2 3 4 5 6 |
#calculate power power = round(ampsA0 * voltsA1,places) print('Power: {0}'.format(power)) #post data to adafruit.io EnergyUsage = aio.feeds('EnergyUsage') aio.send_data('EnergyUsage’, power) |
Для бесплатных аккаунтов сервис adafruit.io требует, чтобы при загрузке или считывании с него данных присутствовала некоторая временная задержка.
1 2 |
# Wait before repeating loop time.sleep(0) |
Тестирование работы проекта
Когда код программы будет готов, сохраните и запустите на выполнение в python IDE. Но перед этим убедитесь в том, что плата Raspberry Pi подключена к сети интернет с помощью WiFi или LAN и ваши ключ доступа (aio key) и имя пользователя (username) корректны. Спустя некоторое время вы должны увидеть как в соответствующем фиде Adafruit.io будет отображаться значение потребляемой мощности. Внешний вид собранного проекта для тестирования у нас выглядит следующим образом:
Для дальнейшего усовершенствования проекта вы можете создать панель инструментов на adafruit.io и добавить в нее компонент построения графиков как показано на следующем рисунке.
Теперь вы можете контролировать потребление энергии в необходимом вам месте из любой точки земного шара где есть подключение к сети интернет. Также в данный проект вы можете добавить более точную настройку и калибровку измерителя электроэнергии чтобы превратить его в практически профессиональный инструмент для измерения потребляемой мощности.
Исходный код программы на Python
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 |
#!/usr/bin/env python3 import time import Adafruit_ADS1x15 from Adafruit_IO import * import math # Create an ADS1115 ADC (16-bit) instance.. (создаем объект для работы с модулем АЦП) adc1 = Adafruit_ADS1x15.ADS1115() username = ‘your-user-name' AIO_KEY = 'your-aio-key’ aio = Client(username, AIO_KEY) GAIN = 1 # see ads1015/1115 documentation for potential values. samples = 5 # number of samples taken from ads1115 (число отсчетов для дискретизации) places = int(2) # set rounding (устанавливаем округление) # создаем бесконечный цикл while чтобы мониторить значения тока и напряжения, рассчитывать потребляемую мощность и передавать ее значение на Adafruit io while True: # reset variables (сбрасываем значения переменных) count = int(0) datai = [] datav = [] maxIValue = 0 maxVValue = 0 IrmsA0 = 0 VrmsA1 = 0 ampsA0 = 0 voltsA1 =0 kilowatts = float(0) # since we are measuring an AC circuit the output of SCT-013 wand the voltage sensor will be a sinewave. (на выходе датчика SCT-013 будет сигнал синусоидальной формы) # in order to calculate amps from sinewave we will need to get the peak voltage (нам необходимо определить пиковое значение этого сигнала) # from each input and use root mean square formula (RMS) (затем определить среднеквадратичное значение полученной величины) # this loop will take 200 samples from each input and give you the highest (peak) (для определения пикового значения мы берем 200 отсчетов сигнала и среди них определяем максимальное значение) for count in range(5): datai.insert(count, (abs(adc1.read_adc(0, gain=GAIN)))) datav.insert(count, (abs(adc1.read_adc(1, gain=GAIN)))) # see if you have a new maxValue print (datai[count]) if datai[count] > maxIValue: maxIValue = datai[count] if datav[count] > maxVValue: maxVValue = datav[count] print("new maxv value:") print(maxVValue) #calculate current using the sampled data (рассчитываем ток) # I used a sct-013 that is calibrated for 1000mV output @ 30A. Usually has 30A/1V printed on it. (выход датчика sct-013 откалиброван на 1000mV при силе тока 30A) print("proceeding") IrmsA0 = float(maxIValue / float(2047) * 30) IrmsA0 = round(IrmsA0, places) ampsA0 = IrmsA0 / math.sqrt(2) # RMS formula to get current reading to match what an ammeter shows. (определяем среднеквадратическое значение тока) ampsA0 = round(ampsA0, places) # Calculate voltage (рассчитываем напряжение) VrmsA1 = float(maxVValue * 1100/ float(2047)) VrmsA1 = round(VrmsA1, places) voltsA1 = VrmsA1 / math.sqrt(2) # RMS formula to get voltage reading to match what an voltmeter shows. (определяем среднеквадратическое значение напряжения) voltsA1 = round(voltsA1, places) print('Voltage: {0}'.format(voltsA1)) print('Current: {0}'.format(ampsA0)) #calculate power (рассчитываем мощность) power = round(ampsA0 * voltsA1,places) print('Power: {0}'.format(power)) #post data to adafruit.io (передаем данные на adafruit.io) energyconsumption = aio.feeds('energyconsumption') aio.send_data('energyconsumption', power) # Wait before repeating loop (задержка перед тем как выполнить цикл снова) time.sleep(30) |