Skip to content

Commit 2f99b0b

Browse files
committed
rewritten for esphome
1 parent a1a5b5c commit 2f99b0b

File tree

10 files changed

+973
-667
lines changed

10 files changed

+973
-667
lines changed

.gitignore

Lines changed: 0 additions & 11 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4-
## [Unreleased]
4+
## [3.0.0] 2023-01-20
5+
This is a completely rewritten implementation. Instead of using the Homie convention and the homie-esp8266 library,
6+
this version is implemented using ESPHome.
7+
8+
BREAKING CHANGES!!!
9+
All the mqtt topics have changed! See README.md for more details.
510

611
## [2.0.0] 2019-06-30
712
Changed to v2.x due to the breaking change in the partition topics

README.md

Lines changed: 111 additions & 182 deletions
Large diffs are not rendered by default.

common.yaml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
esphome:
2+
name: ${device_name}
3+
comment: ${friendly_name}
4+
5+
wifi:
6+
ssid: !secret wifi_ssid
7+
password: !secret wifi_password
8+
reboot_timeout: 1h
9+
# Enable fallback hotspot (captive portal) in case wifi connection fails
10+
ap:
11+
# ssid: "ESPHOME"
12+
ssid: ${device_name}
13+
password: !secret fallback_hotspot_password
14+
15+
captive_portal:
16+
17+
ota:
18+
password: !secret ota_password
19+
20+
logger:
21+
level: INFO
22+
23+
web_server:
24+
port: 80
25+
auth:
26+
username: !secret web_login
27+
password: !secret web_password
28+
29+
switch:
30+
- platform: restart
31+
name: reboot
32+
retain: false
33+
34+
sensor:
35+
- platform: wifi_signal
36+
id: wifi_signal_db
37+
name: rssi
38+
update_interval: 300s
39+
- platform: copy # Reports the WiFi signal strength in %
40+
source_id: wifi_signal_db
41+
name: signal
42+
filters:
43+
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
44+
unit_of_measurement: "Signal %"
45+
- platform: uptime
46+
name: uptime
47+
48+
text_sensor:
49+
- platform: version
50+
name: esphome_version
51+
- platform: wifi_info
52+
ip_address:
53+
name: ip-address
54+
55+
mqtt:
56+
broker: !secret mqtt_broker
57+
discovery: false
58+
reboot_timeout: 1h
59+
id: mqtt_id

dsc-alarm.yaml

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
substitutions:
2+
# Adjust accordingly
3+
device_name: dsc-alarm
4+
friendly_name: Alarm System
5+
6+
timezone: Australia/Brisbane
7+
# set this to your local NTP server if you have one
8+
ntp_server: 2.pool.ntp.org
9+
10+
access_code: !secret alarm_access_code
11+
12+
dsc_clock_pin: D1
13+
dsc_read_pin: D2
14+
dsc_write_pin: D8
15+
16+
max_zone: "6"
17+
max_partition: "1"
18+
19+
esp8266:
20+
# change this to match your board
21+
board: d1_mini
22+
23+
packages:
24+
common: !include common.yaml
25+
26+
esphome:
27+
includes:
28+
- includes/dscAlarm.h
29+
libraries:
30+
- taligentx/dscKeybusInterface@^3.0
31+
32+
ota:
33+
on_begin:
34+
- lambda: ((DSCKeybus*)id(dsc_keybus))->disconnect();
35+
on_error:
36+
- lambda: ((DSCKeybus*)id(dsc_keybus))->connect();
37+
38+
time:
39+
- platform: sntp
40+
id: ntp_time
41+
timezone: ${timezone}
42+
servers: ["${ntp_server}", 0.pool.ntp.org, 1.pool.ntp.org]
43+
on_time_sync:
44+
then:
45+
- lambda: |-
46+
ESP_LOGI("main", "System clock synchronized %s", id(ntp_time).now().strftime("%F %R").c_str());
47+
48+
on_time:
49+
- seconds: 0
50+
minutes: 0
51+
hours: 9
52+
days_of_month: 1
53+
then:
54+
- lambda: |-
55+
auto time = id(ntp_time).now();
56+
ESP_LOGI("main", "Updating Panel time to %s", time.strftime("%F %R").c_str());
57+
((DSCKeybus*)id(dsc_keybus))->setTime(time.year, time.month, time.day_of_month, time.hour, time.minute);
58+
59+
mqtt:
60+
on_connect:
61+
- delay: 1s
62+
- lambda: ((DSCKeybus*)id(dsc_keybus))->resetStatus();
63+
64+
on_message:
65+
- topic: ${device_name}/command
66+
payload: disarm
67+
then:
68+
- lambda: |-
69+
for (auto i = 1; i <= ${max_partition}; i++) {
70+
((DSCKeybus*)id(dsc_keybus))->disarm(i);
71+
}
72+
73+
- topic: ${device_name}/command
74+
payload: arm_away
75+
then:
76+
- lambda: |-
77+
for (auto i = 1; i <= ${max_partition}; i++) {
78+
((DSCKeybus*)id(dsc_keybus))->armAway(i);
79+
}
80+
81+
- topic: ${device_name}/command
82+
payload: arm_stay
83+
then:
84+
- lambda: |-
85+
for (auto i = 1; i <= ${max_partition}; i++) {
86+
((DSCKeybus*)id(dsc_keybus))->armStay(i);
87+
}
88+
89+
- topic: ${device_name}/command
90+
payload: trigger_fire
91+
then:
92+
- lambda: ((DSCKeybus*)id(dsc_keybus))->triggerFireAlarm();
93+
94+
- topic: ${device_name}/command
95+
payload: trigger_panic
96+
then:
97+
- lambda: ((DSCKeybus*)id(dsc_keybus))->triggerPanicAlarm();
98+
99+
- topic: ${device_name}/command
100+
payload: reboot
101+
then:
102+
- lambda: App.safe_reboot();
103+
104+
- topic: ${device_name}/command
105+
payload: reset-status
106+
then:
107+
- lambda: ((DSCKeybus*)id(dsc_keybus))->resetStatus();
108+
109+
- topic: ${device_name}/write
110+
then:
111+
- lambda: ((DSCKeybus*)id(dsc_keybus))->write(x);
112+
113+
# Updates partition 1's time from NTP
114+
- topic: ${device_name}/panel-time/update
115+
payload: now
116+
then:
117+
- lambda: |-
118+
auto time = id(ntp_time).now();
119+
if (time.is_valid()) {
120+
((DSCKeybus*)id(dsc_keybus))->setTime(time.year, time.month, time.day_of_month, time.hour, time.minute);
121+
}
122+
123+
custom_component:
124+
- lambda: |-
125+
auto dscKeybus = new DSCKeybus(${dsc_clock_pin}, ${dsc_read_pin}, ${dsc_write_pin}, "${access_code}");
126+
127+
auto on_or_off = [](bool value) { return (std::string)(value ? "on" : "off"); };
128+
auto extract_number = [](const char *prefix, const std::string &value) {
129+
auto start = strlen(prefix);
130+
auto end = value.find('/', start);
131+
return parse_number<uint8_t>(value.substr(start, end-start)).value_or(0);
132+
};
133+
134+
dscKeybus->onKeybusConnectionChange([&](bool isConnected) {
135+
id(mqtt_id)->publish("${device_name}/keybus", on_or_off(isConnected), 0, true);
136+
});
137+
138+
dscKeybus->onKeypadStatusChange([&](DSCKeybus::KeypadStatus statusType, bool state) {
139+
std::string topic = "${device_name}/";
140+
switch(statusType) {
141+
case DSCKeybus::KeypadStatus::TROUBLE: topic += "trouble"; break;
142+
case DSCKeybus::KeypadStatus::BATTERY_TROUBLE: topic += "battery-trouble"; break;
143+
case DSCKeybus::KeypadStatus::POWER_TROUBLE: topic += "power-trouble"; break;
144+
}
145+
id(mqtt_id)->publish(topic, on_or_off(state), 0, true);
146+
});
147+
148+
dscKeybus->onKeypadAlarm([&](DSCKeybus::KeypadAlarm alarmType) {
149+
std::string type;
150+
switch (alarmType) {
151+
case DSCKeybus::KeypadAlarm::PANIC_ALARM: type = "panic"; break;
152+
case DSCKeybus::KeypadAlarm::AUX_ALARM: type = "aux"; break;
153+
case DSCKeybus::KeypadAlarm::FIRE_ALARM: type = "fire"; break;
154+
}
155+
id(mqtt_id)->publish("${device_name}/keypad/alarm", type);
156+
});
157+
158+
dscKeybus->onPanelTimeChange([&](std::string time) {
159+
id(mqtt_id)->publish("${device_name}/panel-time", time);
160+
});
161+
162+
dscKeybus->onLightStatusChange([&](uint8_t partition, byte lights) {
163+
if (partition > ${max_partition}) {
164+
return;
165+
}
166+
167+
static byte previousLights[${max_partition}];
168+
169+
std::string topic = str_sprintf("${device_name}/partition/%d/lights/", partition);
170+
const char* lightNames[] = { "ready", "armed", "memory", "bypass", "trouble", "program", "fire", "backlight" };
171+
172+
for (byte i = 0; i < 8; i++) {
173+
bool light = bitRead(lights, i);
174+
if (light != bitRead(previousLights[partition-1], i)) {
175+
id(mqtt_id)->publish(topic + lightNames[i], on_or_off(light));
176+
}
177+
}
178+
179+
previousLights[partition - 1] = lights;
180+
});
181+
182+
dscKeybus->onPartitionArmedChange([&](uint8_t partition, bool armed, bool armedStay, bool armedAway) {
183+
if (partition > ${max_partition}) {
184+
return;
185+
}
186+
187+
std::string topic = str_sprintf("${device_name}/partition/%d/", partition);
188+
id(mqtt_id)->publish(topic + "armed", on_or_off(armed), 0, true);
189+
id(mqtt_id)->publish(topic + "armed-stay", on_or_off(armedStay), 0, true);
190+
id(mqtt_id)->publish(topic + "armed-away", on_or_off(armedAway), 0, true);
191+
});
192+
193+
id(mqtt_id)->subscribe("${device_name}/partition/+/armed/set", [=](const std::string &topic, const std::string &payload) {
194+
auto partition = extract_number("${device_name}/partition/", topic);
195+
if (partition > dscPartitions) {
196+
ESP_LOGE("main", "Partition out of range: %d", partition);
197+
return;
198+
}
199+
200+
switch(parse_on_off(payload.c_str())) {
201+
case PARSE_ON: dscKeybus->armAway(partition); break;
202+
case PARSE_OFF: dscKeybus->disarm(partition); break;
203+
}
204+
});
205+
206+
dscKeybus->onPartitionAlarmChange([&](uint8_t partition, bool triggered) {
207+
if (partition > ${max_partition}) {
208+
return;
209+
}
210+
211+
std::string topic = str_sprintf("${device_name}/partition/%d/alarm", partition);
212+
id(mqtt_id)->publish(topic, on_or_off(triggered), 0, true);
213+
});
214+
215+
dscKeybus->onPartitionStatusChange([&](uint8_t partition, DSCKeybus::PartitionStatus statusCode) {
216+
if (partition > ${max_partition}) {
217+
return;
218+
}
219+
std::string status;
220+
switch(statusCode) {
221+
case DSCKeybus::PartitionStatus::DISARMED: status = "disarmed"; break;
222+
case DSCKeybus::PartitionStatus::ARMED_STAY: status = "armed_stay"; break;
223+
case DSCKeybus::PartitionStatus::ARMED_AWAY: status = "armed_away"; break;
224+
case DSCKeybus::PartitionStatus::EXIT_DELAY: status = "exit_delay"; break;
225+
case DSCKeybus::PartitionStatus::TRIGGERED: status = "triggered"; break;
226+
}
227+
std::string topic = str_sprintf("${device_name}/partition/%d/state", partition);
228+
id(mqtt_id)->publish(topic, status, 0, true);
229+
});
230+
231+
dscKeybus->onZoneStatusChange([&](uint8_t zone, bool state) {
232+
if (zone > ${max_zone}) {
233+
return;
234+
}
235+
std::string topic = str_sprintf("${device_name}/zone/%d/motion", zone);
236+
id(mqtt_id)->publish(topic, on_or_off(state));
237+
});
238+
239+
dscKeybus->onZoneAlarmChange([&](uint8_t zone, bool state) {
240+
if (zone > ${max_zone}) {
241+
return;
242+
}
243+
std::string topic = str_sprintf("${device_name}/zone/%d/alarm", zone);
244+
id(mqtt_id)->publish(topic, on_or_off(state));
245+
});
246+
247+
return {dscKeybus};
248+
249+
components:
250+
- id: dsc_keybus

0 commit comments

Comments
 (0)