Skip to content

Commit

Permalink
Merge remote
Browse files Browse the repository at this point in the history
  • Loading branch information
taligentx committed Jun 13, 2018
2 parents af68826 + 955bc04 commit 9111133
Show file tree
Hide file tree
Showing 19 changed files with 172 additions and 51 deletions.
180 changes: 129 additions & 51 deletions examples/Arduino/Status-MQTT-HomeAssistant/Status-MQTT-HomeAssistant.ino
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
/*
* DSC Status with MQTT (Arduino)
* DSC Status with MQTT (Arduino, esp8266)
*
* Processes the security system status and allows for control using Home Assistant via MQTT.
*
* Home Assistant: https://www.home-assistant.io
* Mosquitto MQTT broker: https://mosquitto.org
*
* In this example, the commands to set the alarm state are setup in Home Assistant as:
* For a single partition, the commands to set the alarm state are setup in Home Assistant as:
* Disarm: "D"
* Arm stay: "S"
* Arm away: "A"
*
* The interface listens for commands in the configured mqttSubscibeTopic, and publishes alarm states to the
* configured mqttPublishTopic:
* For multiple partitions, add the partition number as a prefix to the command:
* Partition 1 disarm: "1D"
* Partition 2 arm stay: "2S"
* Partition 2 arm away: "2A"
*
* The interface listens for commands in the configured mqttSubscribeTopic, and publishes partition status in a
* separate topic per partition with the configured mqttPartitionTopic appended with the partition number:
* Disarmed: "disarmed"
* Arm stay: "armed_home"
* Arm away: "armed_away"
Expand All @@ -24,6 +29,11 @@
* Closed: "0"
* Open: "1"
*
* Fire states are published in a separate topic per partition with the configured mqttFireTopic appended with the
* partition number. The fire state is published as an integer:
* "0": fire alarm restored
* "1": fire alarm tripped
*
* Example Home Assistant configuration.yaml:
# https://www.home-assistant.io/components/mqtt/
Expand All @@ -32,15 +42,34 @@
client_id: homeAssistant
# https://www.home-assistant.io/components/alarm_control_panel.mqtt/
# Single partition example:
alarm_control_panel:
- platform: mqtt
name: "Security System"
state_topic: "dsc/Get"
state_topic: "dsc/Get/Partition1"
command_topic: "dsc/Set"
payload_disarm: "D"
payload_arm_home: "S"
payload_arm_away: "A"
# Multiple partition example:
alarm_control_panel:
- platform: mqtt
name: "Security System Partition 1"
state_topic: "dsc/Get/Partition1"
command_topic: "dsc/Set"
payload_disarm: "1D"
payload_arm_home: "1S"
payload_arm_away: "1A"
alarm_control_panel:
- platform: mqtt
name: "Security System Partition 2"
state_topic: "dsc/Get/Partition2"
command_topic: "dsc/Set"
payload_disarm: "2D"
payload_arm_home: "2S"
payload_arm_away: "2A"
# https://www.home-assistant.io/components/binary_sensor/
binary_sensor:
- platform: mqtt
Expand All @@ -57,7 +86,7 @@
payload_off: "0"
- platform: mqtt
name: "Smoke Alarm"
state_topic: "dsc/Get/Fire"
state_topic: "dsc/Get/Fire1"
device_class: "smoke"
payload_on: "1"
payload_off: "0"
Expand Down Expand Up @@ -96,8 +125,7 @@
* This example code is in the public domain.
*/

#include <SPI.h>
#include <Ethernet.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <dscKeybusInterface.h>

Expand All @@ -115,20 +143,21 @@ const char* mqttPassword = "";
const char* accessCode = ""; // An access code is required to disarm/night arm and may be required to arm based on panel configuration.

const char* mqttClientName = "dscKeybusInterface";
const char* mqttPublishTopic = "dsc/Get"; // Sends partition armed and alarm status
const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to write to the panel
const char* mqttZoneTopic = "dsc/Get/Zone"; // Sends zone status - the zone number will be appended to this topic name: dsc/Get/Zone1 ... dsc/Get/Zone64
const char* mqttFireTopic = "dsc/Get/Fire"; // Sends fire status
const char* mqttPartitionTopic = "dsc/Get/Partition"; // Sends armed and alarm status per partition: dsc/Get/Partition1 ... dsc/Get/Partition8
const char* mqttZoneTopic = "dsc/Get/Zone"; // Sends zone status per zone: dsc/Get/Zone1 ... dsc/Get/Zone64
const char* mqttFireTopic = "dsc/Get/Fire"; // Sends fire status per partition: dsc/Get/Fire1 ... dsc/Get/Fire8
const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to write to the panel
unsigned long mqttPreviousTime;

EthernetClient ethClient;
PubSubClient mqtt(ethClient);

// Configures the Keybus interface with the specified pins - dscWritePin is
// optional, leaving it out disables the virtual keypad
// Not using PIN4 on Arduino, as some ethernet shields use it.
#define dscClockPin 3
#define dscReadPin 4
#define dscWritePin 5
#define dscReadPin 5
#define dscWritePin 6
dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin);


Expand All @@ -150,7 +179,6 @@ void setup() {
mqtt.setClient(ethClient);
mqtt.setServer(mqttServer, 1883);
mqtt.setCallback(mqttCallback);

if (mqttConnect()) mqttPreviousTime = millis();
else mqttPreviousTime = 0;

Expand All @@ -167,45 +195,84 @@ void loop() {

if (dsc.handlePanel() && dsc.statusChanged) { // Processes data only when a valid Keybus command has been read
dsc.statusChanged = false; // Reset the status tracking flag

// Sends the access code when needed by the panel for arming
if (dsc.accessCodePrompt && dsc.writeReady) {
dsc.accessCodePrompt = false;
dsc.write(accessCode);
}


// If the Keybus data buffer is exceeded, the sketch is too busy to process all Keybus commands. Call
// handlePanel() more often, or increase dscBufferSize in the library: src/dscKeybusInterface.h
if (dsc.bufferOverflow) Serial.println(F("Keybus buffer overflow"));
dsc.bufferOverflow = false;

// Publishes exit delay status
if (dsc.exitDelayChanged) {
dsc.exitDelayChanged = false; // Resets the exit delay status flag
if (dsc.exitDelay) mqtt.publish(mqttPublishTopic, "pending", true); // Publish as a retained message
// Sends the access code when needed by the panel for arming
if (dsc.accessCodePrompt && dsc.writeReady) {
dsc.accessCodePrompt = false;
dsc.write(accessCode);
}

// Publishes armed status
if (dsc.partitionArmedChanged) {
dsc.partitionArmedChanged = false; // Resets the partition armed status flag
if (dsc.partitionArmed) {
if (dsc.partitionArmedAway) mqtt.publish(mqttPublishTopic, "armed_away", true);
else if (dsc.partitionArmedStay) mqtt.publish(mqttPublishTopic, "armed_home", true);
// Publishes status per partition
for (byte partitionIndex = 0; partitionIndex < dscPartitions; partitionIndex++) {

// Publishes exit delay status
if (dsc.exitDelayChanged[partitionIndex]) {
dsc.exitDelayChanged[partitionIndex] = false; // Resets the exit delay status flag

// Appends the mqttPartitionTopic with the partition number
char publishTopic[strlen(mqttPartitionTopic) + 1];
char partition[2];
strcpy(publishTopic, mqttPartitionTopic);
itoa(partitionIndex + 1, partition, 10);
strcat(publishTopic, partition);

if (dsc.exitDelay[partitionIndex]) mqtt.publish(publishTopic, "pending", true); // Publish as a retained message
else if (!dsc.exitDelay[partitionIndex] && !dsc.armed[partitionIndex]) mqtt.publish(publishTopic, "disarmed", true);
}
else mqtt.publish(mqttPublishTopic, "disarmed", true);
}

// Publishes alarm status
if (dsc.partitionAlarmChanged) {
dsc.partitionAlarmChanged = false; // Resets the partition alarm status flag
if (dsc.partitionAlarm) mqtt.publish(mqttPublishTopic, "triggered", true);
}
// Publishes armed/disarmed status
if (dsc.armedChanged[partitionIndex]) {
dsc.armedChanged[partitionIndex] = false; // Resets the partition armed status flag

// Appends the mqttPartitionTopic with the partition number
char publishTopic[strlen(mqttPartitionTopic) + 1];
char partition[2];
strcpy(publishTopic, mqttPartitionTopic);
itoa(partitionIndex + 1, partition, 10);
strcat(publishTopic, partition);

if (dsc.armed[partitionIndex]) {
if (dsc.armedAway[partitionIndex]) mqtt.publish(publishTopic, "armed_away", true);
else if (dsc.armedStay[partitionIndex]) mqtt.publish(publishTopic, "armed_home", true);
}
else mqtt.publish(publishTopic, "disarmed", true);
}

// Publishes alarm status
if (dsc.alarmChanged[partitionIndex]) {
dsc.alarmChanged[partitionIndex] = false; // Resets the partition alarm status flag
if (dsc.alarm[partitionIndex]) {

// Appends the mqttPartitionTopic with the partition number
char publishTopic[strlen(mqttPartitionTopic) + 1];
char partition[2];
strcpy(publishTopic, mqttPartitionTopic);
itoa(partitionIndex + 1, partition, 10);
strcat(publishTopic, partition);

mqtt.publish(publishTopic, "triggered", true); // Alarm tripped
}
}

// Publishes the fire alarm status
if (dsc.fireStatusChanged) {
dsc.fireStatusChanged = false; // Resets the fire alarm status flag
if (dsc.fireStatus) mqtt.publish(mqttFireTopic, "1"); // Fire alarm tripped
else mqtt.publish(mqttFireTopic, "0"); // Fire alarm restored
// Publishes alarm status
if (dsc.fireChanged[partitionIndex]) {
dsc.fireChanged[partitionIndex] = false; // Resets the fire status flag

// Appends the mqttFireTopic with the partition number
char firePublishTopic[strlen(mqttFireTopic) + 1];
char partition[2];
strcpy(firePublishTopic, mqttFireTopic);
itoa(partitionIndex + 1, partition, 10);
strcat(firePublishTopic, partition);

if (dsc.fire[partitionIndex]) mqtt.publish(firePublishTopic, "1"); // Fire alarm tripped
else mqtt.publish(firePublishTopic, "0"); // Fire alarm restored
}
}

// Publishes zones 1-64 status in a separate topic per zone
Expand All @@ -216,7 +283,7 @@ void loop() {
// openZones[7] and openZonesChanged[7]: Bit 0 = Zone 57 ... Bit 7 = Zone 64
if (dsc.openZonesStatusChanged) {
dsc.openZonesStatusChanged = false; // Resets the open zones status flag
for (byte zoneGroup = 0; zoneGroup < 8; zoneGroup++) {
for (byte zoneGroup = 0; zoneGroup < dscZones; zoneGroup++) {
for (byte zoneBit = 0; zoneBit < 8; zoneBit++) {
if (bitRead(dsc.openZonesChanged[zoneGroup], zoneBit)) { // Checks an individual open zone status flag
bitWrite(dsc.openZonesChanged[zoneGroup], zoneBit, 0); // Resets the individual open zone status flag
Expand Down Expand Up @@ -249,21 +316,33 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
(void)topic;
(void)length;

byte partitionIndex = 0;
byte payloadIndex = 0;

// Checks if a partition number 1-8 has been sent and sets the second character as the payload
if (payload[0] >= 0x31 && payload[0] <= 0x38) {
partitionIndex = payload[0] - 49;
payloadIndex = 1;
}

// Arm stay
if (payload[0] == 'S' && !dsc.partitionArmed && !dsc.exitDelay) {
if (payload[payloadIndex] == 'S' && !dsc.armed[partitionIndex] && !dsc.exitDelay[partitionIndex]) {
while (!dsc.writeReady) dsc.handlePanel(); // Continues processing Keybus data until ready to write
dsc.writePartition = partitionIndex + 1; // Sets writes to the partition number
dsc.write('s'); // Virtual keypad arm stay
}

// Arm away
else if (payload[0] == 'A' && !dsc.partitionArmed && !dsc.exitDelay) {
while (!dsc.writeReady) dsc.handlePanel();
else if (payload[payloadIndex] == 'A' && !dsc.armed[partitionIndex] && !dsc.exitDelay[partitionIndex]) {
while (!dsc.writeReady) dsc.handlePanel(); // Continues processing Keybus data until ready to write
dsc.writePartition = partitionIndex + 1; // Sets writes to the partition number
dsc.write('w'); // Virtual keypad arm away
}

// Disarm
else if (payload[0] == 'D' && (dsc.partitionArmed || dsc.exitDelay)) {
while (!dsc.writeReady) dsc.handlePanel();
else if (payload[payloadIndex] == 'D' && (dsc.armed[partitionIndex] || dsc.exitDelay[partitionIndex])) {
while (!dsc.writeReady) dsc.handlePanel(); // Continues processing Keybus data until ready to write
dsc.writePartition = partitionIndex + 1; // Sets writes to the partition number
dsc.write(accessCode);
}
}
Expand Down Expand Up @@ -297,4 +376,3 @@ bool mqttConnect() {
}
return mqtt.connected();
}

14 changes: 14 additions & 0 deletions schematics/arduino/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Arduino UNO Shield Single Sided PCB

![single sided pcb](pcb_screenshot.png "Arduino UNO Shield Single Sided PCB")

### Parts List

|Amount|Part Type|Properties|
|--- |--- |--- |
|2|Screw terminal - 2 pins|pin spacing 0.137in (3.5mm); pins 2; hole size 1.0mm,0.508mm|
|1|NPN-Transistor|2N3904|
|2|15kΩ Resistor|resistance 15kΩ|
|2|10kΩ Resistor|resistance 10kΩ|
|1|1kΩ Resistor|resistance 1kΩ|
|1|Arduino UNO|Revision 3|
Binary file added schematics/arduino/etch_copper_top.pdf
Binary file not shown.
Binary file added schematics/arduino/etch_copper_top_mirror.pdf
Binary file not shown.
Binary file added schematics/arduino/etch_silk_top.pdf
Binary file not shown.
Binary file added schematics/arduino/etch_silk_top_mirror.pdf
Binary file not shown.
Binary file added schematics/arduino/pcb_screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions schematics/esp8266/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
## NodeMCU (esp8266) Single Sided PCB

![single sided pcb](pcb_screenshot.png "NodeMCU (esp8266) Single Sided PCB")

### Parts List

|Amount|Part Type|Properties|
|--- |--- |--- |
|1|Ceramic Capacitor|capacitance 100nF|
|2|Screw terminal - 2 pins|pin spacing 0.137in (3.5mm); pins 2; hole size 1.0mm,0.508mm|
|1|Voltage Regulator - 3.3 V|LM1117|
|1|NPN-Transistor|2N3904|
|2|15kΩ Resistor|resistance 15kΩ|
|2|10kΩ Resistor|resistance 10kΩ|
|1|1kΩ Resistor|resistance 1kΩ|
|1|NodeMCU V3.0|chip ESP8266|
Binary file added schematics/esp8266/etch_copper_top.pdf
Binary file not shown.
Binary file added schematics/esp8266/etch_copper_top_mirror.pdf
Binary file not shown.
Binary file added schematics/esp8266/etch_silk_top.pdf
Binary file not shown.
Binary file added schematics/esp8266/etch_silk_top_mirror.pdf
Binary file not shown.
Binary file added schematics/esp8266/pcb_screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions schematics/simple/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Simple Single Sided PCB

![simple single sided pcb](pcb_screenshot.png "Simple Single Sided PCB")

### Parts List

|Amount|Part Type|Properties|
|--- |--- |--- |
|4|Screw terminal - 2 pins|pin spacing 0.137in (3.5mm); pins 2; hole size 1.0mm,0.508mm|
|1|NPN-Transistor|2N3904|
|2|15kΩ Resistor|resistance 15kΩ|
|2|10kΩ Resistor|resistance 10kΩ|
|1|1kΩ Resistor|resistance 1kΩ|
Binary file added schematics/simple/etch_copper_top.pdf
Binary file not shown.
Binary file added schematics/simple/etch_copper_top_mirror.pdf
Binary file not shown.
Binary file added schematics/simple/etch_silk_top.pdf
Binary file not shown.
Binary file added schematics/simple/etch_silk_top_mirror.pdf
Binary file not shown.
Binary file added schematics/simple/pcb_screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 9111133

Please sign in to comment.