Skip to content

Commit

Permalink
Add Telegram bot example #135, handle disarming Panic alarms in MQTT …
Browse files Browse the repository at this point in the history
…examples, support message prefix in notification examples, use root certificate for Pushbullet connections
  • Loading branch information
taligentx committed Dec 22, 2020
1 parent b65b792 commit 4002f2f
Show file tree
Hide file tree
Showing 36 changed files with 2,055 additions and 802 deletions.
29 changes: 17 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ This library directly interfaces Arduino, esp8266, and esp32 microcontrollers to

The built-in examples can be used as-is or as a base to adapt to other uses:
* Home automation integration: [Home Assistant](https://www.home-assistant.io), [Apple HomeKit & Siri](https://www.apple.com/ios/home/), [OpenHAB](https://www.openhab.org), [Athom Homey](https://www.athom.com/en/)
* Notifications: [PushBullet](https://www.pushbullet.com), [Twilio SMS](https://www.twilio.com), MQTT, E-mail
* Direct control: Web interface, [Blynk](https://www.blynk.cc) mobile app
* Installer code: automatic code search to unlock panels with unknown installer codes
* Notifications: [Telegram](https://www.telegram.org) bot, [PushBullet](https://www.pushbullet.com), [Twilio SMS](https://www.twilio.com), E-mail
* Virtual keypad: Web interface, [Blynk](https://www.blynk.cc) mobile app
* Installer code unlocking: automatic code search to unlock panels with unknown installer codes

See the [dscKeybusInterface-RTOS](https://github.com/taligentx/dscKeybusInterface-RTOS) repository for a port of this library to [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos) - this enables a standalone esp8266 HomeKit accessory using [esp-homekit](https://github.com/maximkulkin/esp-homekit).

Expand All @@ -14,12 +14,14 @@ Screenshots:
![HomeKit](https://user-images.githubusercontent.com/12835671/61570833-c9bb9780-aa54-11e9-9477-8e0853609e91.png)
* [Home Assistant](https://www.home-assistant.io):
![HomeAssistant](https://user-images.githubusercontent.com/12835671/61985900-38f33780-afd1-11e9-9d43-ab0b681b7b03.png)
* [OpenHAB](https://www.openhab.org):
* [OpenHAB](https://www.openhab.org) MQTT:
![OpenHAB](https://user-images.githubusercontent.com/12835671/61560425-daa6e180-aa31-11e9-9efe-0fcb44d2106a.png)
* [Blynk](https://www.blynk.cc) app virtual keypad:
![VirtualKeypad-Blynk](https://user-images.githubusercontent.com/12835671/61568638-9fb0a800-aa49-11e9-94d0-e598431ea2ed.png)
* Web virtual keypad:
![VirtualKeypad-Web](https://user-images.githubusercontent.com/12835671/61570049-e43f4200-aa4f-11e9-96bc-3448b6630990.png)
* [Telegram](https://www.telegram.org) bot:
![Telegram](https://user-images.githubusercontent.com/12835671/102907524-c8598000-443b-11eb-81f0-18bc42306cbb.png)

## Why?
**I Had**: _A DSC security system not being monitored by a third-party service._
Expand Down Expand Up @@ -77,13 +79,13 @@ Poking around with a logic analyzer and oscilloscope revealed that the errors ca
* Development boards: NodeMCU ESP-32S, Doit ESP32 Devkit v1, Wemos Lolin D32, etc.
* Includes [Arduino framework support](https://github.com/espressif/arduino-esp32), dual cores, WiFi, and Bluetooth for ~$5USD shipped.
* Possible features (PRs welcome!):
- Virtual zone expander: Add new zones to the DSC panel emulated by the microcontroller based on GPIO pin states or software-based states. Requires decoding the DSC PC5108 zone expander data.
- [DSC IT-100](https://cms.dsc.com/download.php?t=1&id=16238) emulation
- Unlock 6-digit installer codes
- DSC Classic series support: This protocol is [already decoded](https://github.com/dougkpowers/pc1550-interface), use with this library would require major changes.

## Release notes
* develop
- New: [Telegram](https://www.telegram.org) bot example sketch
- New: [OpenHAB](https://www.openhab.org) integration example sketch using MQTT
- New: `Unlocker` example sketch - determines the panel installer code
- New: `KeybusReaderIP` example sketch enables Keybus data access over IP, thanks to [aboulfad](https://github.com/aboulfad) for this contribution!
Expand Down Expand Up @@ -171,6 +173,7 @@ The included examples demonstrate how to use the library and can be used as-is o
* Partitions fire alarm
* Zones open/closed
* Zones in alarm
* PGM outputs 1-14
* Keypad fire/auxiliary/panic alarm
* Get/set panel date and time
* User access code number (1-40)
Expand All @@ -179,20 +182,22 @@ The included examples demonstrate how to use the library and can be used as-is o
* Panel trouble
* Keybus connected

* **Homebridge-MQTT**: Integrates with Apple HomeKit, including the iOS Home app and Siri. This uses MQTT to interface with [Homebridge](https://github.com/nfarina/homebridge) and [homebridge-mqttthing](https://github.com/arachnetech/homebridge-mqttthing) and demonstrates using the armed and alarm states for the HomeKit securitySystem object, zone states for the contactSensor objects, and fire alarm states for the smokeSensor object.
* **Homebridge-MQTT**: Interfaces with [Homebridge](https://github.com/nfarina/homebridge) via MQTT to integrate with Apple HomeKit (including the iOS Home app and Siri). Demonstrates arming/disarming partitions and viewing the status of zones, PGM outputs, and fire alarms.
- The [dscKeybusInterface-RTOS](https://github.com/taligentx/dscKeybusInterface-RTOS) library includes a native HomeKit implementation that runs directly on esp8266, without requiring a separate device running MQTT or Homebridge.

* **HomeAssistant-MQTT**: Integrates with [Home Assistant](https://www.home-assistant.io) via MQTT. This uses the armed and alarm states for the HomeAssistant [Alarm Control Panel](https://www.home-assistant.io/components/alarm_control_panel.mqtt) component, as well as zone, fire alarm, and trouble states for the [Binary Sensor](https://www.home-assistant.io/components/binary_sensor.mqtt) component. For esp8266/esp32, a partition status message is also sent as a sensor component.
* **HomeAssistant-MQTT**: Interfaces with [Home Assistant](https://www.home-assistant.io) via MQTT. Demonstrates arming/disarming partitions and viewing the status of zones, PGM outputs, fire alarms, and trouble. For esp8266/esp32, the partition status is available as a text message for display.

* **OpenHAB-MQTT**: Integrates with [OpenHAB](https://www.openhab.org) via MQTT. This uses the [OpenHAB MQTT binding](https://www.openhab.org/addons/bindings/mqtt/) and demonstrates using the panel and partitions states as OpenHAB switches and zone states as OpenHAB contacts. For esp8266/esp32, a panel status message is also sent as a string to OpenHAB. See https://github.com/jimtng/dscalarm-mqtt for an integration using the Homie convention for OpenHAB's Homie MQTT component.
* **OpenHAB-MQTT**: Interfaces with [OpenHAB](https://www.openhab.org) via MQTT. Demonstrates using the panel and partitions states as OpenHAB switches and zone states as OpenHAB contacts. For esp8266/esp32, a panel status message is also sent as a string to OpenHAB. See https://github.com/jimtng/dscalarm-mqtt for an integration using the Homie convention for OpenHAB's Homie MQTT component.

* **Homey**: Integrates with [Athom Homey](https://www.athom.com/en/) and the [Homeyduino](https://github.com/athombv/homey-arduino-library/) library, including armed, alarm, and fire states (currently limited to one partition), and zone states. Thanks to [MagnusPer](https://github.com/MagnusPer) for contributing this example!

* **Pushbullet** (esp8266/esp32-only): Demonstrates how to send a push notification when the status has changed. This example sends notifications via [Pushbullet](https://www.pushbullet.com) and requires the esp8266/esp32 for SSL support.
* **Telegram** (esp8266/esp32-only): Demonstrates sending status updates and arming/disarming the security system via a [Telegram](https://www.telegram.org) bot.

* **Twilio-SMS** (esp8266/esp32-only): Demonstrates how to send an SMS text message when the status has changed. This example sends texts via [Twilio](https://www.twilio.com) and requires the esp8266/esp32 for SSL support - thanks to [ColingNG](https://github.com/ColinNg) for contributing this example!
* **Pushbullet** (esp8266/esp32-only): Demonstrates sending status updates as a push notification via [Pushbullet](https://www.pushbullet.com).

* **Email** (esp8266/esp32-only): Demonstrates how to send an email when the status has changed. Email is sent using SMTPS (port 465) with SSL for encryption - this is necessary on the esp8266/esp32 until STARTTLS can be supported. For example, this will work with Gmail after changing the account settings to [allow less secure apps](https://support.google.com/accounts/answer/6010255).
* **Twilio-SMS** (esp8266/esp32-only): Demonstrates sending status updates as an SMS text message via [Twilio](https://www.twilio.com) - thanks to [ColingNG](https://github.com/ColinNg) for contributing this example!

* **Email** (esp8266/esp32-only): Demonstrates sending status updates as an email. Email is sent using SMTPS (port 465) with SSL for encryption - this is necessary on the esp8266/esp32 until STARTTLS can be supported. For example, this will work with Gmail after changing the account settings to [allow less secure apps](https://support.google.com/accounts/answer/6010255).

This can be used to send SMS text messages if the number's service provider has an [email to SMS gateway](https://en.wikipedia.org/wiki/SMS_gateway#Email_clients) - examples for the US:
* T-mobile: 5558675309@tmomail.net
Expand All @@ -206,7 +211,7 @@ The included examples demonstrate how to use the library and can be used as-is o

Note: Installing [Blynk as a local server](https://github.com/blynkkk/blynk-server) is recommended to keep control of the security system internal to your network. This also lets you use as many widgets as needed for free - local servers can setup users with any amount of Blynk Energy. Using the default Blynk cloud service with the above example layouts requires more of Blynk's Energy units than available on the free usage tier.

* **VirtualKeypad-Web** (esp8266-only): Provides a virtual keypad web interface, using the esp8266 itself as a standalone web server. This example uses the [ESP Async Web Server](https://github.com/me-no-dev/ESPAsyncWebServer) and Websockets - thanks to [Elektrik1](https://github.com/Elektrik1) for contributing this example!
* **VirtualKeypad-Web** (esp8266-only): Provides a virtual keypad web interface, using the esp8266 itself as a standalone web server - thanks to [Elektrik1](https://github.com/Elektrik1) for contributing this example!

* **Unlocker**: Checks all possible 4-digit installer codes until a valid code is found, including handling keypad lockout if enabled. The valid code is output to serial as well as repeatedly flashed with the built-in LED.

Expand Down
25 changes: 12 additions & 13 deletions examples/Arduino/HomeAssistant-MQTT/HomeAssistant-MQTT.ino
Original file line number Diff line number Diff line change
Expand Up @@ -215,17 +215,17 @@ unsigned long mqttPreviousTime;

void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println();

// Initializes ethernet with DHCP
Serial.print(F("Initializing Ethernet..."));
Serial.print(F("Ethernet...."));
while(!Ethernet.begin(mac)) {
Serial.println(F("DHCP failed. Retrying..."));
delay(5000);
}
Serial.println(F("success!"));
Serial.print(F("IP address: "));
Serial.print(F("connected: "));
Serial.println(Ethernet.localIP());

mqtt.setCallback(mqttCallback);
Expand All @@ -235,7 +235,6 @@ void setup() {
// Starts the Keybus interface and optionally specifies how to print data.
// begin() sets Serial by default and can accept a different stream: begin(Serial1), etc.
dsc.begin();

Serial.println(F("DSC Keybus Interface is online."));
}

Expand Down Expand Up @@ -282,7 +281,6 @@ void loop() {

// Publishes armed/disarmed status
if (dsc.armedChanged[partition]) {
dsc.armedChanged[partition] = false; // Resets the partition armed status flag
char publishTopic[strlen(mqttPartitionTopic) + 2];
appendPartition(mqttPartitionTopic, partition, publishTopic); // Appends the mqttPartitionTopic with the partition number

Expand All @@ -308,13 +306,13 @@ void loop() {
// Publishes alarm status
if (dsc.alarmChanged[partition]) {
dsc.alarmChanged[partition] = false; // Resets the partition alarm status flag
if (dsc.alarm[partition]) {
char publishTopic[strlen(mqttPartitionTopic) + 2];
appendPartition(mqttPartitionTopic, partition, publishTopic); // Appends the mqttPartitionTopic with the partition number
char publishTopic[strlen(mqttPartitionTopic) + 2];
appendPartition(mqttPartitionTopic, partition, publishTopic); // Appends the mqttPartitionTopic with the partition number

mqtt.publish(publishTopic, "triggered", true); // Alarm tripped
}
if (dsc.alarm[partition]) mqtt.publish(publishTopic, "triggered", true); // Alarm tripped
else if (!dsc.armedChanged[partition]) mqtt.publish(publishTopic, "disarmed", true);
}
if (dsc.armedChanged[partition]) dsc.armedChanged[partition] = false; // Resets the partition armed status flag

// Publishes fire alarm status
if (dsc.fireChanged[partition]) {
Expand Down Expand Up @@ -430,7 +428,7 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
}

// Disarm
else if (payload[payloadIndex] == 'D' && (dsc.armed[partition] || dsc.exitDelay[partition])) {
else if (payload[payloadIndex] == 'D' && (dsc.armed[partition] || dsc.exitDelay[partition] || dsc.alarm[partition])) {
dsc.writePartition = partition + 1; // Sets writes to the partition number
dsc.write(accessCode);
}
Expand All @@ -454,13 +452,14 @@ void mqttHandle() {


bool mqttConnect() {
Serial.print(F("MQTT...."));
if (mqtt.connect(mqttClientName, mqttUsername, mqttPassword, mqttStatusTopic, 0, true, mqttLwtMessage)) {
Serial.print(F("MQTT connected: "));
Serial.print(F("connected: "));
Serial.println(mqttServer);
dsc.resetStatus(); // Resets the state of all status components as changed to get the current status
}
else {
Serial.print(F("MQTT connection failed: "));
Serial.print(F("connection error: "));
Serial.println(mqttServer);
}
return mqtt.connected();
Expand Down
18 changes: 9 additions & 9 deletions examples/Arduino/Homebridge-MQTT/Homebridge-MQTT.ino
Original file line number Diff line number Diff line change
Expand Up @@ -216,17 +216,17 @@ char exitState;

void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println();

// Initializes ethernet with DHCP
Serial.print(F("Initializing Ethernet..."));
Serial.print(F("Ethernet...."));
while(!Ethernet.begin(mac)) {
Serial.println(F("DHCP failed. Retrying..."));
delay(5000);
}
Serial.println(F("success!"));
Serial.print(F("IP address: "));
Serial.print(F("connected: "));
Serial.println(Ethernet.localIP());

mqtt.setCallback(mqttCallback);
Expand All @@ -236,7 +236,6 @@ void setup() {
// Starts the Keybus interface and optionally specifies how to print data.
// begin() sets Serial by default and can accept a different stream: begin(Serial1), etc.
dsc.begin();

Serial.println(F("DSC Keybus Interface is online."));
}

Expand Down Expand Up @@ -270,8 +269,6 @@ void loop() {

// Publishes armed/disarmed status
if (dsc.armedChanged[partition]) {
dsc.armedChanged[partition] = false; // Resets the partition armed status flag

if (dsc.armed[partition]) {
exitState = 0;

Expand Down Expand Up @@ -343,7 +340,9 @@ void loop() {
if (dsc.alarm[partition]) {
publishState(mqttPartitionTopic, partition, 0, "T");
}
else if (!dsc.armedChanged[partition]) publishState(mqttPartitionTopic, partition, "D", "D");
}
if (dsc.armedChanged[partition]) dsc.armedChanged[partition] = false; // Resets the partition armed status flag

// Publishes fire alarm status
if (dsc.fireChanged[partition]) {
Expand Down Expand Up @@ -478,7 +477,7 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
}

// homebridge-mqttthing DISARM
if (payload[payloadIndex] == 'D' && (dsc.armed[partition] || dsc.exitDelay[partition])) {
if (payload[payloadIndex] == 'D' && (dsc.armed[partition] || dsc.exitDelay[partition] || dsc.alarm[partition])) {
dsc.writePartition = partition + 1; // Sets writes to the partition number
dsc.write(accessCode);
return;
Expand All @@ -503,13 +502,14 @@ void mqttHandle() {


bool mqttConnect() {
Serial.print(F("MQTT...."));
if (mqtt.connect(mqttClientName, mqttUsername, mqttPassword)) {
Serial.print(F("MQTT connected: "));
Serial.print(F("connected: "));
Serial.println(mqttServer);
dsc.resetStatus(); // Resets the state of all status components as changed to get the current status
}
else {
Serial.print(F("MQTT connection failed: "));
Serial.print(F("connection error: "));
Serial.println(mqttServer);
}
return mqtt.connected();
Expand Down
2 changes: 1 addition & 1 deletion examples/Arduino/KeybusReader/KeybusReader.ino
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin);

void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println();

Expand All @@ -64,7 +65,6 @@ void setup() {
// Starts the Keybus interface and optionally specifies how to print data.
// begin() sets Serial by default and can accept a different stream: begin(Serial1), etc.
dsc.begin();

Serial.println(F("DSC Keybus Interface is online."));
}

Expand Down
18 changes: 9 additions & 9 deletions examples/Arduino/OpenHAB-MQTT/OpenHAB-MQTT.ino
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,17 @@ unsigned long mqttPreviousTime;

void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println();

// Initializes ethernet with DHCP
Serial.print(F("Initializing Ethernet..."));
Serial.print(F("Ethernet...."));
while(!Ethernet.begin(mac)) {
Serial.println(F("DHCP failed. Retrying..."));
delay(5000);
}
Serial.println(F("success!"));
Serial.print(F("IP address: "));
Serial.print(F("connected: "));
Serial.println(Ethernet.localIP());

mqtt.setCallback(mqttCallback);
Expand All @@ -174,7 +174,6 @@ void setup() {
// Starts the Keybus interface and optionally specifies how to print data.
// begin() sets Serial by default and can accept a different stream: begin(Serial1), etc.
dsc.begin();

Serial.println(F("DSC Keybus Interface is online."));
}

Expand Down Expand Up @@ -221,8 +220,6 @@ void loop() {

// Publishes armed/disarmed status
if (dsc.armedChanged[partition]) {
dsc.armedChanged[partition] = false; // Resets the partition armed status flag

if (dsc.armed[partition]) {

// Armed away
Expand Down Expand Up @@ -256,7 +253,9 @@ void loop() {
if (dsc.alarm[partition]) {
publishState(mqttPartitionTopic, partition, "T");
}
else if (!dsc.armedChanged[partition]) publishState(mqttPartitionTopic, partition, "D");
}
if (dsc.armedChanged[partition]) dsc.armedChanged[partition] = false; // Resets the partition armed status flag

// Publishes fire alarm status
if (dsc.fireChanged[partition]) {
Expand Down Expand Up @@ -370,7 +369,7 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
}

// Disarm
if (payload[payloadIndex] == 'D' && (dsc.armed[partition] || dsc.exitDelay[partition])) {
if (payload[payloadIndex] == 'D' && (dsc.armed[partition] || dsc.exitDelay[partition] || dsc.alarm[partition])) {
dsc.writePartition = partition + 1; // Sets writes to the partition number
dsc.write(accessCode);
return;
Expand All @@ -396,13 +395,14 @@ void mqttHandle() {


bool mqttConnect() {
Serial.print(F("MQTT...."));
if (mqtt.connect(mqttClientName, mqttUsername, mqttPassword, mqttStatusTopic, 0, true, mqttLwtMessage)) {
Serial.print(F("MQTT connected: "));
Serial.print(F("connected: "));
Serial.println(mqttServer);
dsc.resetStatus(); // Resets the state of all status components as changed to get the current status
}
else {
Serial.print(F("MQTT connection failed: "));
Serial.print(F("connection error: "));
Serial.println(mqttServer);
}
return mqtt.connected();
Expand Down
Loading

0 comments on commit 4002f2f

Please sign in to comment.