Організація аварійного освітлення в під’їзді
Привіт усім! Хочу поділитися досвідом мого друга та колеги Влада Хоменчука зі створення системи аварійного освітлення в під’їзді. Це рішення стане в пригоді під час блекаутів або у випадках, коли з якоїсь причини в під’їзді відсутнє освітлення. Така система допомагає підсвітити шлях біля ніг, щоб не доводилося рухатися наосліп. Усі деталі можна придбати на AliExpress.
Дві світлодіодні стрічки 5В споживають 115 мА·год. При використанні UPS на 10 000 мА·год такого освітлення має вистачити на 86 годин.
Наявність електроенергії визначається за допомогою фотодіода. Mini UPS має світлодіод, який відображає статус живлення: зелений (світло є) і червоний (світла немає). Фоторезистор має максимальну чутливість до зеленого кольору, тоді як на червоний колір його чутливість майже нульова. Мікроконтролер фіксує різницю в чутливості до цих кольорів і визначає стан наявності електроенергії.
Серверна частина обраховує час сходу заходу сонця, надає час, та подає MQTT команди на ESP. Сервери зараз коштують не дорого, а цей проєкт Влад запускав на безкоштовній VPS від Oracle. Від себе також пораджу безкоштовний план Render (750 год безкоштовної роботи (31 доба) та 100 Гб вихідного трафіку. Машина 512 МБ RAM та 0.1 CPU).
- Block 1 Стрічка не реагує на зміну кольору, у проміжку часу дня та комендантської години.
- Block 0 дозволяє вмикати та вимикати стрічку в залежності від наявності електроенергії.
- Block 3 (запускається від команди від MQTT клієнта) світлодіодна стрічка минає двічі і потім запитує у сервера поточний статус блоку щоб повернутись до 0 чи до 1.
- Block 4 (запускається від команди від MQTT клієнта) вмикає світлодіодну стрічку. Block 4

Система складається з:
DC Mini UPS 5v 18650 (10 000 мА·год)
Фоторезистор
Node MCU ESP8266
Одноканальне реле 5V
Резистор 1 кОм
Cвітлодіодна стрічка 5V (fairy lights) — 30 м — 2 шт
Micro USB-DC кабелю для живлення ESP
Та USB A кабелю подовжувача


Arduino код на ESP8266
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "****";
const char* password = "****";
const char* mqtt_server = "***.**.***.***";
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
unsigned long lastMsg2 = 0;
uint8_t block = 99;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
randomSeed(micros());
}
void callback(char* topic, byte* payload, unsigned int length) {
if ((char)payload[0] == '0') block = 0;
if ((char)payload[0] == '1') { block = 1; digitalWrite(D5,LOW); }
if ((char)payload[0] == '2') block = 2;
if ((char)payload[0] == '3') block = 3;
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
client.subscribe("moonlight/block");
while (block == 99)
{ delay(500);
client.publish("moonlight/wakeup", "wakeup");
client.loop();
}
} else {
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
pinMode(D5, OUTPUT);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
if (now - lastMsg > 250) {
lastMsg = now;
if (block == 0){ // Розблокувати і вмикати відносно значання A0
if (analogRead(A0)>590)
{
digitalWrite(D5,HIGH);
}else
{
digitalWrite(D5,LOW);
}
}
if (block == 2){ // мигнути
digitalWrite(D5,HIGH);
delay(500);
digitalWrite(D5,LOW);
delay(500);
digitalWrite(D5,HIGH);
delay(500);
digitalWrite(D5,LOW);
delay(500);
client.publish("moonlight/wakeup", "wakeup");
}
if (block == 3){ // горіти
digitalWrite(D5,HIGH);
}
}
if (now - lastMsg2 > 600000) {
lastMsg2 = now;
client.publish("moonlight/wakeup", "wakeup");
}
}
Python код, що запускається на сервері
#!/usr/bin/python3
import paho.mqtt.subscribe as subscribe
import paho.mqtt.publish as publish
import ephem, datetime
def datetime_to_cron(ts):
dt = datetime.datetime.fromtimestamp(ts)
return f"{dt.minute} {dt.hour} * * * "
x = 0.01
kyiv = ephem.city('Kiev')
obs = ephem.Observer()
obs.lat = kyiv.lat
obs.long= kyiv.long
sun = ephem.Sun()
obs.date = (datetime.datetime.now() - datetime.timedelta(days=1))
rise_time = obs.next_rising(sun)
set_time = obs.next_setting(sun)
suntime = ephem.localtime(set_time).timestamp()-ephem.localtime(rise_time).timestamp()
end = int(ephem.localtime(rise_time).timestamp()-suntime*x)
start = int(ephem.localtime(set_time).timestamp()+suntime*x)
def on_wakeup():
#print("wakeup")
global end
global start
# комендантська година
if datetime.datetime.now().hour in range(5): # 00:00-4:59
publish.single("moonlight/block", "1", hostname="localhost")
return
if datetime.datetime.now().timestamp() > end and datetime.datetime.now().timestamp() < start:
publish.single("moonlight/block", "1", hostname="localhost")
else:
publish.single("moonlight/block", "0", hostname="localhost")
def on_change_time():
#print("change_time")
global end
global start
global obs
global x
obs.date = datetime.datetime.now()
rise_time = obs.next_rising(sun)
set_time = obs.next_setting(sun)
suntime = ephem.localtime(set_time).timestamp()-ephem.localtime(rise_time).timestamp()
end = int(ephem.localtime(rise_time).timestamp()+suntime*x)
start = int(ephem.localtime(set_time).timestamp()-suntime*x)
with open("/var/spool/cron/crontabs/moonlight", "w") as file1:
file1.write(datetime_to_cron(end)+"mosquitto_pub -t moonlight/block -m 1\n")
file1.write(datetime_to_cron(start)+"mosquitto_pub -t moonlight/block -m 0\n")
# комендантська година!
file1.write("10 0 * * * mosquitto_pub -t moonlight/block -m 1\n")
file1.write("50 4 * * * mosquitto_pub -t moonlight/block -m 0\n")
def on_req(client, userdata, message):
if "/wakeup" in str(message.topic.encode('utf-8')):
on_wakeup()
if "/time" in str(message.topic.encode('utf-8')):
on_change_time()
subscribe.callback(on_req, "moonlight/#", hostname="localhost", userdata={"message_count": 0})
24 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарів