Как стать автором
Обновить

Контроль уровня заряда батарей raspberry pi с выводом аудио оповещения

Время на прочтение5 мин
Количество просмотров4.4K
Возникла ситуация, когда необходимо выводить звук-предупреждение о разряде ибп raspberry pi.
В статье предлагается решение с использованием датчика напряжения (Voltage Sensor), arduino nano и «любимой аудио колонки школьника» — портативной «jbl go».

*c 26 секунды

ИБП


Пара слов об используемом источнике бесперебойного питания. Для электроснабжения raspberry pi 4 был приобретен ибп, от которого одноплатник на двух аккумуляторах 18650 может держаться аж 3,5 часа:



*картинка выбрана из эстетических соображений и внешне немного отличается от варианта для raspberry pi 4:



Для варианта под raspberry pi 4 есть выход type-c для питания raspberry pi, а также monitor напряжения (на фото расположен справа), который пригодится в дальнейшем.
Этот ИБП не идеален, но он лучше аналогичных, которыми приходилось пользоваться с того же ali.

Есть два нюанса, о которых нужно помнить при его использовании.

Первый нюанс — необходимо иметь под рукой блок питания на 12 V 2А (или 3А), потому как при смене «батарей» (аккумуляторов, конечно, но далее по тексту — батареи), ибп входит в блокировку и чтобы из нее вывести нужно подать 12В, подключив блок питания к ибп. Батареи можно из ибп не вынимать и заряжать/подзаряжать их прямо в ибп, тогда не придется выводить из блокировки.

Второй нюанс — при вставке батарей в держатели ибп не нужно ориентироваться на нарисованные на пластике крупные "+" и "-", они немного перепутаны:



Тем не менее, если батареи вставить неправильно, то на приборе просто загорится светодиод, предупреждая об этом, и прибор снова уйдет в блокировку.

Ах, да, добавлю еще третий нюанс — при выключении raspberry, ибп не обесточивается, продолжая работать и необходимо вручную передвинуть рычажок на нем «on/off». И это было бы пол-беды. Если забыть про рычажок, ибп, продолжая работать, со временем «высадит» батареи.
В остальном ИБП хорош.

Взять хотя бы usb разъемы и выводы с 5V для питания периферии.

Но эта статья не про ибп, поэтому двигаемся дальше.

Как определить разряд батарей


Как известно, на raspberry pi нет своего ацп, поэтому нужен определенный огород, чтобы снимать прямо с нее показатели. Мне не захотелось паяться на gpio raspberry, тем более, что на них уже висит «шапка», поэтому пошел через старое-доброе arduino nano. Хотя хотелось взять более мелкий вариант на tiny85 — digispark. Но у digispark есть вопросы с выводом информации в serial, поэтому пока arduino nano.

На ИБП есть выход с названием «Monitor», и интуитивно понятно, что он должен что-то говорить о напряжении на ибп. Однако, найти документацию по этому выходу либо ответ на вопрос через соц. сети не удалось. Тем не менее, опытным путем было выяснено, что на ноге «low bat» этого монитора возникает напряжение, когда батареи ибп разряжены. При этом на самом ибп загорается светодиод.

Выглядит это примерно так (результат работы скетча из данной статьи):



Поэтому, эту информацию и будем мониторить.

Arduino nano скетч


Так как в бой пойдет arduino nano, то и скетч для нее.

int analogPin = A0;                 // Указываем порт OUT датчика 

const int averageValue = 500;       // Переменная для хранения значения количества считывания циклов 
long int sensorValue = 0;           // Переменная для хранения значения с датчика

float voltage = 0;                  // Переменная для хранения значения напряжения
float current = 0;                  // Переменная для хранения значения тока

void setup() 
{
  Serial.begin(9600);               //  Открываем последовательную связь на скорости 9600
}

void loop() 
{
  for (int i = 0; i < averageValue; i++)    // Повторяем цикл
  {
    sensorValue += analogRead(analogPin);   // Считываем и записываем показания
    delay(2);                               // Пауза 2 мкс
  }

  sensorValue = sensorValue / averageValue; // Делим полученное значение 
  voltage = sensorValue * 5.0 / 1024.0;     // Расчет напряжения
  current = (voltage - 2.5) / 0.185;        // Расчет тока

  Serial.print("ADC Value: ");              // Отправка данных в последовательный порт
  Serial.print(sensorValue);

  Serial.print("   ADC Voltage: ");         // Отправка данных в последовательный порт
  Serial.print(voltage);                    // Отправка напряжения
  Serial.print("V");                        // Отправка данных в последовательный порт

  Serial.print("   Current: ");             // Отправка данных в последовательный порт
  Serial.print(current);                    // Отправка тока
  Serial.println("A");                      // Отправка данных в последовательный порт
}

Тут все предельно просто и щедро усыпано комментариями. Все, что нужно знать A0 — pin arduino, сама arduino подключается через usb port к raspberry.

Кстати, некоторые китайские nano не шьются простым методом через arduino ide и на них надо
зажимать reset во время компиляции скетча и отпускать его когда в ide загорится «загрузка».
Естественно, это связано не содержанием скетча, а со спецификой arduino nano от ali.

Соединяем компоненты


Как уже упоминалось, для мониторинга используется датчик напряжения (Voltage Sensor):


и лучше брать без распаянных клемм, т.к. они слишком громоздкие. Сам датчик неприхотлив, однако дает искажения при воздействии на него магнитом и другими непотребными вещами.

Итак GND порта Monitor ИБП -> "-" клемма(!) датчика,
«low bat» порта Monitor ИБП -> "+" клемма(!) датчика.
«S» датчика -> A0 arduino nano,
"+" датчика -> 5V arduino nano,
"-" датчика -> GND arduino nano.



Часть raspberry pi


Пришла очередь raspberry pi, на которую через usb port от arduino будут приходить показания с датчика.

После подключения arduino для начала проверим, что вообще что-то приходит в порт:

#! /usr/bin/env python
# coding: utf-8
import serial
#python -m serial.tools.list_ports 
ser = serial.Serial("/dev/ttyS0",baudrate=9600,timeout=0.1)
ser.flush()
print(ser)
while True :
    line = ser.readline().decode().strip()
    if line:
        print(line)
ser.close()

Если в консоль выводятся значения, то все в порядке. Если нет, то необходимо поменять порт "/dev/ttyS0".

Теперь напишем основной скрипт, который будет делать всю работу и добавим его в servicemd.
Содержание следующее:

#! /usr/bin/env python
# coding: utf-8
import schedule
 
#speech speak
from rhvoice_wrapper import TTS;import subprocess
from time import sleep

###языковая часть
def say(text):
    data = tts.get(text, format_='wav') 
    #print('data size: ', len(data), ' bytes')
    subprocess.check_output(['aplay', '-r','16000','-q'], input=data) 

tts = TTS(threads=1)

import serial
#python -m serial.tools.list_ports 
#ser = serial.Serial("/dev/ttyS0",baudrate=9600,timeout=0.1)
def func():
    """open serial every ___ min and check voltage drop"""
    ser = serial.Serial("/dev/ttyUSB0",baudrate=9600,timeout=0.1)
    ser.flush()
    #print(ser)    
     
    while True :
        try:
            line = ser.readline().decode().strip()
            if line:
                print(line.split(' ')[7].strip('V'))
                if float(line.split(' ')[7].strip('V')) >0.5:
                    print('разряжено')
                    say('разряжено')                
                    ser.close()
                    return False
        except:
            pass    
    ser.close()


if __name__ == "__main__":
    schedule.every(1).minutes.do(func)
  
    while True:
        schedule.run_pending()
        sleep(1)

В части озвучивания используется rhvoice_wrapper, который нужно будет установить через pip install.

Также понадобится schedule, который тоже через pip install.

Суть скрипта — каждую минуту открывается serial порт, читается значение датчика и если оно больше 0.5 (if float(line.split(' ')[7].strip('V')) >0.5), то произносится «разряжено».

Каждую минуту делать это не обязательно, поэтому в строке schedule.every(1).minutes.do(func) можно поменять значение.

Теперь добавим этот скрипт в servicemd raspberry pi:

sudo nano /etc/systemd/system/charge_check.service

И внесем содержимое:

[Unit]
Description=charge_check   
After=multi-user.target
[Service]
User=pi
Type=simple
Restart=always
RestartSec=5
WorkingDirectory=/home/pi/Desktop
ExecStart=/usr/bin/python3 charge_check.py
[Install]
WantedBy=multi-user.target

Если скрипт лежит не на Deskrop и называется не charge_check.py, то эти моменты нужно поправить.

Перезагружаем демонов и запускаем свой сервис:

sudo systemctl daemon-reload
sudo systemctl enable charge_check.service
sudo systemctl start charge_check.service

Проверим, что сервис работает:



Если сервис не работает, то можно посмотреть, что ему не нравится следующей командой:

journalctl -u charge_check.service -b

На этом все, спасибо за внимание.
Теги:
Хабы:
Всего голосов 3: ↑3 и ↓0+3
Комментарии14

Публикации

Истории

Работа

Python разработчик
136 вакансий
Data Scientist
60 вакансий

Ближайшие события