From ee09e9e6309510ccb1e2e6629dc11d878bc89dc3 Mon Sep 17 00:00:00 2001 From: Nikhil Choudhary Date: Mon, 28 Dec 2020 13:15:02 -0600 Subject: [PATCH] Add TimeSyncNTP example, add optional partition to setTime(), unify all network examples with same client name --- README.md | 36 +++--- .../HomeAssistant-MQTT/HomeAssistant-MQTT.ino | 6 +- .../Homebridge-MQTT/Homebridge-MQTT.ino | 6 +- .../Arduino/KeybusReader/KeybusReader.ino | 60 +++++---- .../Arduino/OpenHAB-MQTT/OpenHAB-MQTT.ino | 6 +- examples/Arduino/Status/Status.ino | 15 ++- examples/Arduino/Unlocker/Unlocker.ino | 2 +- examples/esp32/Email/Email.ino | 58 ++++----- .../HomeAssistant-MQTT/HomeAssistant-MQTT.ino | 6 +- .../esp32/Homebridge-MQTT/Homebridge-MQTT.ino | 6 +- examples/esp32/Homey/Homey.ino | 2 +- examples/esp32/KeybusReader/KeybusReader.ino | 60 +++++---- examples/esp32/OpenHAB-MQTT/OpenHAB-MQTT.ino | 6 +- examples/esp32/Pushbullet/Pushbullet.ino | 54 ++++---- examples/esp32/Status/Status.ino | 15 ++- examples/esp32/Telegram/Telegram.ino | 8 +- examples/esp32/Twilio-SMS/Twilio-SMS.ino | 64 +++++----- examples/esp32/Unlocker/Unlocker.ino | 2 +- .../VirtualKeypad-Blynk.ino | 2 +- examples/esp8266/Email/Email.ino | 60 ++++----- .../HomeAssistant-MQTT/HomeAssistant-MQTT.ino | 6 +- .../Homebridge-MQTT/Homebridge-MQTT.ino | 6 +- examples/esp8266/Homey/Homey.ino | 2 +- .../esp8266/KeybusReader/KeybusReader.ino | 60 +++++---- .../esp8266/KeybusReaderIP/KeybusReaderIP.ino | 115 ++++++++++-------- .../esp8266/OpenHAB-MQTT/OpenHAB-MQTT.ino | 6 +- examples/esp8266/Pushbullet/Pushbullet.ino | 54 ++++---- examples/esp8266/Status/Status.ino | 15 ++- examples/esp8266/Telegram/Telegram.ino | 8 +- examples/esp8266/Twilio-SMS/Twilio-SMS.ino | 66 +++++----- examples/esp8266/Unlocker/Unlocker.ino | 2 +- .../VirtualKeypad-Blynk.ino | 2 +- .../VirtualKeypad-Web/VirtualKeypad-Web.ino | 2 +- src/dscKeybusInterface.cpp | 14 ++- src/dscKeybusInterface.h | 3 +- src/dscKeybusPrintData.cpp | 22 ++-- src/dscKeybusProcessData.cpp | 19 ++- 37 files changed, 479 insertions(+), 397 deletions(-) diff --git a/README.md b/README.md index b8f3623..4f3c103 100644 --- a/README.md +++ b/README.md @@ -10,33 +10,33 @@ The built-in examples can be used as-is or as a base to adapt to other uses: 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). Screenshots: -* [Apple Home & Siri](https://www.apple.com/ios/home/): +* [Apple Home & Siri](https://www.apple.com/ios/home/): ![HomeKit](https://user-images.githubusercontent.com/12835671/61570833-c9bb9780-aa54-11e9-9477-8e0853609e91.png) -* [Home Assistant](https://www.home-assistant.io): +* [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) MQTT: +* [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: +* [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: +* 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://www.telegram.org) bot: ![Telegram](https://user-images.githubusercontent.com/12835671/102932636-47fc4480-4466-11eb-844b-baa767b92157.png) ## Quick start 1. Install the DSC Keybus Interface library: - * Arduino IDE: Search for `DSC` in the Library Manager - `Sketch > Include Library > Manage Libraries` + * Arduino IDE: Search for `DSC` in the Library Manager - `Sketch > Include Library > Manage Libraries` ![ArduinoIDE](https://user-images.githubusercontent.com/12835671/41826133-cfa55334-77ec-11e8-8ee1-b482cdb696b2.png) - * PlatformIO IDE: Search for `DSC` in the [PlatformIO Library Registry](https://platformio.org/lib/show/5499/dscKeybusInterface) + * PlatformIO IDE: Search for `DSC` in the [PlatformIO Library Registry](https://platformio.org/lib/show/5499/dscKeybusInterface) ![PlatformIO](https://user-images.githubusercontent.com/12835671/41826138-d5852b62-77ec-11e8-805d-7c861a329e43.png) * PlatformIO CLI: `platformio lib install "dscKeybusInterface"` * Alternatively, `git clone` or download the repo .zip to the Arduino/PlatformIO library directory to keep track of the latest changes. -2. Select, configure, and upload one of the example sketches to the microcontroller: +2. Select, configure, and upload one of the example sketches to the microcontroller: ![Examples](https://user-images.githubusercontent.com/12835671/102936214-61ed5580-446d-11eb-9d70-0eae40fe5757.png) 3. Connect the microcontroller to the DSC Keybus per the wiring diagram with the appropriate resistors (and a transistor if you'd like to control the system). ## Why? -**I Had**: _A DSC security system not being monitored by a third-party service._ +**I Had**: _A DSC security system not being monitored by a third-party service._ **I Wanted**: _Notification if the alarm triggered._ I was interested in finding a solution that directly accessed the pair of data lines that DSC uses for their proprietary Keybus protocol to send data between the panel, keypads, and other modules. Tapping into the data lines is an ideal task for a microcontroller and also presented an opportunity to work with the [Arduino](https://www.arduino.cc) and [FreeRTOS](https://www.freertos.org) (via [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos)) platforms. @@ -100,6 +100,8 @@ Poking around with a logic analyzer and oscilloscope revealed that the errors ca - 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: `TimeSyncNTP` example sketch - uses NTP to automatically set the panel time + - New: [ESPHome](https://esphome.io) integration example (located in the `extras` directory) - thanks to [Dilbert66](https://github.com/Dilbert66) for this contribution! - New: `KeybusReaderIP` example sketch enables Keybus data access over IP, thanks to [aboulfad](https://github.com/aboulfad) for this contribution! - New: esp32 microcontroller support - New: Features for sketches: @@ -194,13 +196,15 @@ The included examples demonstrate how to use the library and can be used as-is o * **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. +* **ESPHome** (esp8266): Integrates with [ESPHome](https://esphome.io) as a custom component - note that this example is located in the `extras` directory. Thanks to [Dilbert66](https://github.com/Dilbert66) for this contribution! + * **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! -* **Telegram** (esp8266/esp32-only): Demonstrates sending status updates and arming/disarming the security system via a [Telegram](https://www.telegram.org) bot. +* **Telegram** (esp8266/esp32): Demonstrates sending status updates and arming/disarming the security system via a [Telegram](https://www.telegram.org) bot. -* **Pushbullet** (esp8266/esp32-only): Demonstrates sending status updates as a push notification via [Pushbullet](https://www.pushbullet.com). +* **Pushbullet** (esp8266/esp32): Demonstrates sending status updates as a push notification via [Pushbullet](https://www.pushbullet.com). -* **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! +* **Twilio-SMS** (esp8266/esp32): 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). @@ -210,13 +214,15 @@ The included examples demonstrate how to use the library and can be used as-is o * Sprint: 5558675309@messaging.sprintpcs.com * AT&T: 5558675309@txt.att.net -* **VirtualKeypad-Blynk** (esp8266/esp32-only): Provides a virtual keypad interface for the free [Blynk](https://www.blynk.cc) app on iOS and Android. Scan one of the following QR codes from within the Blynk app for an example keypad layout: +* **VirtualKeypad-Blynk** (esp8266/esp32): Provides a virtual keypad interface for the free [Blynk](https://www.blynk.cc) app on iOS and Android. Scan one of the following QR codes from within the Blynk app for an example keypad layout: - [Virtual keypad with 16 zones](https://user-images.githubusercontent.com/12835671/42364287-41ca6662-80c0-11e8-85e7-d579b542568d.png) - [Virtual keypad with 32 zones](https://user-images.githubusercontent.com/12835671/42364293-4512b720-80c0-11e8-87bd-153c4e857b4e.png) 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 - thanks to [Elektrik1](https://github.com/Elektrik1) for contributing this example! +* **VirtualKeypad-Web** (esp8266): 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! + +* **TimeSyncNTP**: Synchronizes and maintains the panel time via an NTP server, including DST adjustments. * **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. diff --git a/examples/Arduino/HomeAssistant-MQTT/HomeAssistant-MQTT.ino b/examples/Arduino/HomeAssistant-MQTT/HomeAssistant-MQTT.ino index c3f3a91..cb1d5c3 100644 --- a/examples/Arduino/HomeAssistant-MQTT/HomeAssistant-MQTT.ino +++ b/examples/Arduino/HomeAssistant-MQTT/HomeAssistant-MQTT.ino @@ -203,13 +203,13 @@ const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to w // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 3 // Arduino Uno hardware interrupt pin: 2,3 -#define dscReadPin 5 // Arduino Uno: 2-12 +#define dscReadPin 5 // Arduino Uno: 2-12 #define dscWritePin 6 // Arduino Uno: 2-12 // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -EthernetClient ethClient; -PubSubClient mqtt(mqttServer, mqttPort, ethClient); +EthernetClient ipClient; +PubSubClient mqtt(mqttServer, mqttPort, ipClient); unsigned long mqttPreviousTime; diff --git a/examples/Arduino/Homebridge-MQTT/Homebridge-MQTT.ino b/examples/Arduino/Homebridge-MQTT/Homebridge-MQTT.ino index 8b2f949..8d7761c 100644 --- a/examples/Arduino/Homebridge-MQTT/Homebridge-MQTT.ino +++ b/examples/Arduino/Homebridge-MQTT/Homebridge-MQTT.ino @@ -203,13 +203,13 @@ const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to w // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 3 // Arduino Uno hardware interrupt pin: 2,3 -#define dscReadPin 5 // Arduino Uno: 2-12 +#define dscReadPin 5 // Arduino Uno: 2-12 #define dscWritePin 6 // Arduino Uno: 2-12 // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -EthernetClient ethClient; -PubSubClient mqtt(mqttServer, mqttPort, ethClient); +EthernetClient ipClient; +PubSubClient mqtt(mqttServer, mqttPort, ipClient); unsigned long mqttPreviousTime; char exitState; diff --git a/examples/Arduino/KeybusReader/KeybusReader.ino b/examples/Arduino/KeybusReader/KeybusReader.ino index ed61728..3a4ccc2 100644 --- a/examples/Arduino/KeybusReader/KeybusReader.ino +++ b/examples/Arduino/KeybusReader/KeybusReader.ino @@ -6,7 +6,8 @@ * to productive use. * * Release notes: - * 1.2 - Show redundant data by default + * 1.2 - Handle spurious data while keybus is disconnected + * Removed redundant data processing * 1.0 - Initial release * * Wiring: @@ -43,7 +44,7 @@ // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 3 // Arduino Uno hardware interrupt pin: 2,3 -#define dscReadPin 5 // Arduino Uno: 2-12 +#define dscReadPin 5 // Arduino Uno: 2-12 #define dscWritePin 6 // Arduino Uno: 2-12 // Initialize components @@ -75,6 +76,17 @@ void loop() { if (dsc.loop()) { + if (dsc.statusChanged) { // Checks if the security system status has changed + dsc.statusChanged = false; // Reset the status tracking flag + + // Checks if the interface is connected to the Keybus + if (dsc.keybusChanged) { + dsc.keybusChanged = false; // Resets the Keybus data status flag + if (dsc.keybusConnected) Serial.println(F("Keybus connected")); + else Serial.println(F("Keybus disconnected")); + } + } + // If the Keybus data buffer is exceeded, the sketch is too busy to process all Keybus commands. Call // loop() more often, or increase dscBufferSize in the library: src/dscKeybusInterface.h if (dsc.bufferOverflow) { @@ -83,37 +95,37 @@ void loop() { } // Prints panel data - printTimestamp(); - Serial.print(" "); - dsc.printPanelBinary(); // Optionally prints without spaces: printPanelBinary(false); - Serial.print(" ["); - dsc.printPanelCommand(); // Prints the panel command as hex - Serial.print("] "); - dsc.printPanelMessage(); // Prints the decoded message - Serial.println(); - - // Prints keypad and module data when valid panel data is printed - if (dsc.handleModule()) { + if (dsc.keybusConnected) { printTimestamp(); Serial.print(" "); - dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); - Serial.print(" "); - dsc.printModuleMessage(); // Prints the decoded message + dsc.printPanelBinary(); // Optionally prints without spaces: printPanelBinary(false); + Serial.print(" ["); + dsc.printPanelCommand(); // Prints the panel command as hex + Serial.print("] "); + dsc.printPanelMessage(); // Prints the decoded message Serial.println(); + + // Prints keypad and module data when valid panel data is printed + if (dsc.handleModule()) printModule(); } } // Prints keypad and module data when valid panel data is not available - else if (dsc.handleModule()) { - printTimestamp(); - Serial.print(" "); - dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); - Serial.print(" "); - dsc.printModuleMessage(); - Serial.println(); - } + else if (dsc.keybusConnected && dsc.handleModule()) printModule(); } + +// Prints keypad and module data +void printModule() { + printTimestamp(); + Serial.print(" "); + dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); + Serial.print(" "); + dsc.printModuleMessage(); // Prints the decoded message + Serial.println(); +} + + // Prints a timestamp in seconds (with 2 decimal precision) - this is useful to determine when // the panel sends a group of messages immediately after each other due to an event. void printTimestamp() { diff --git a/examples/Arduino/OpenHAB-MQTT/OpenHAB-MQTT.ino b/examples/Arduino/OpenHAB-MQTT/OpenHAB-MQTT.ino index 08c4a3e..0221207 100644 --- a/examples/Arduino/OpenHAB-MQTT/OpenHAB-MQTT.ino +++ b/examples/Arduino/OpenHAB-MQTT/OpenHAB-MQTT.ino @@ -142,13 +142,13 @@ const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to w // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 3 // Arduino Uno hardware interrupt pin: 2,3 -#define dscReadPin 5 // Arduino Uno: 2-12 +#define dscReadPin 5 // Arduino Uno: 2-12 #define dscWritePin 6 // Arduino Uno: 2-12 // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -EthernetClient ethClient; -PubSubClient mqtt(mqttServer, mqttPort, ethClient); +EthernetClient ipClient; +PubSubClient mqtt(mqttServer, mqttPort, ipClient); unsigned long mqttPreviousTime; diff --git a/examples/Arduino/Status/Status.ino b/examples/Arduino/Status/Status.ino index bd56596..4f2dadb 100644 --- a/examples/Arduino/Status/Status.ino +++ b/examples/Arduino/Status/Status.ino @@ -44,7 +44,7 @@ // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 3 // Arduino Uno hardware interrupt pin: 2,3 -#define dscReadPin 5 // Arduino Uno: 2-12 +#define dscReadPin 5 // Arduino Uno: 2-12 #define dscWritePin 6 // Arduino Uno: 2-12 // Initialize components @@ -269,11 +269,14 @@ void loop() { } } - // Checks for a panel timestamp - // - // The panel time can be set using dsc.setTime(year, month, day, hour, minute, "accessCode") - for example: - // dsc.setTime(2015, 10, 21, 7, 28, "1234") # Sets 2015.10.21 07:28 with access code 1234 - // + /* Checks for a panel timestamp + * + * The panel time can be set using dsc.setTime(year, month, day, hour, minute, "accessCode", partition) - the + * partition is optional and defaults to partition 1: + * + * dsc.setTime(2015, 12, 21, 20, 38, "1234") # Sets 2015.12.21 20:38 with access code 1234 + * dsc.setTime(2020, 05, 30, 15, 22, "1234", 2) # Sets 2020.05.30 15:22 with access code 1234 on partition 2 + */ if (dsc.timestampChanged) { dsc.timestampChanged = false; Serial.print(F("Timestamp: ")); diff --git a/examples/Arduino/Unlocker/Unlocker.ino b/examples/Arduino/Unlocker/Unlocker.ino index 21b7d38..c74f6a0 100644 --- a/examples/Arduino/Unlocker/Unlocker.ino +++ b/examples/Arduino/Unlocker/Unlocker.ino @@ -83,7 +83,7 @@ // Configures the Keybus interface with the specified pins #define dscClockPin 3 // Arduino Uno hardware interrupt pin: 2,3 -#define dscReadPin 5 // Arduino Uno: 2-12 +#define dscReadPin 5 // Arduino Uno: 2-12 #define dscWritePin 6 // Arduino Uno: 2-12 #define dscRelayPin 7 // Arduino Uno: 2-12 - Optional, leave this pin disconnected if not using a relay diff --git a/examples/esp32/Email/Email.ino b/examples/esp32/Email/Email.ino index 0896289..8e3a0e6 100644 --- a/examples/esp32/Email/Email.ino +++ b/examples/esp32/Email/Email.ino @@ -50,11 +50,11 @@ const char* messagePrefix = "[Security system] "; // Set a prefix for all messa // Configures the Keybus interface with the specified pins. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin); -WiFiClientSecure wifiClient; +WiFiClientSecure ipClient; bool wifiConnected = true; @@ -195,37 +195,37 @@ void loop() { // server - the login and password must be base64 encoded. For example, on the macOS/Linux terminal: // $ echo -n 'mylogin@example.com' | base64 -w 0 bool sendMessage(const char* messageContent) { - if (!wifiClient.connect("smtp.example.com", 465)) return false; // Set the SMTP server address - for example: smtp.gmail.com + if (!ipClient.connect("smtp.example.com", 465)) return false; // Set the SMTP server address - for example: smtp.gmail.com if(!smtpValidResponse()) return false; - wifiClient.println(F("HELO ESP32")); + ipClient.println(F("HELO ESP32")); if(!smtpValidResponse()) return false; - wifiClient.println(F("AUTH LOGIN")); + ipClient.println(F("AUTH LOGIN")); if(!smtpValidResponse()) return false; - wifiClient.println(F("myBase64encodedLogin")); // Set the SMTP server login in base64 + ipClient.println(F("myBase64encodedLogin")); // Set the SMTP server login in base64 if(!smtpValidResponse()) return false; - wifiClient.println(F("myBase64encodedPassword")); // Set the SMTP server password in base64 + ipClient.println(F("myBase64encodedPassword")); // Set the SMTP server password in base64 if(!smtpValidResponse()) return false; - wifiClient.println(F("MAIL FROM:")); // Set the sender address + ipClient.println(F("MAIL FROM:")); // Set the sender address if(!smtpValidResponse()) return false; - wifiClient.println(F("RCPT TO:")); // Set the recipient address - repeat to add multiple recipients + ipClient.println(F("RCPT TO:")); // Set the recipient address - repeat to add multiple recipients if(!smtpValidResponse()) return false; - wifiClient.println(F("RCPT TO:")); // An optional additional recipient + ipClient.println(F("RCPT TO:")); // An optional additional recipient if(!smtpValidResponse()) return false; - wifiClient.println(F("DATA")); + ipClient.println(F("DATA")); if(!smtpValidResponse()) return false; - wifiClient.println(F("From: Security System ")); // Set the sender displayed in the email header - wifiClient.println(F("To: Recipient ")); // Set the recipient displayed in the email header - wifiClient.print(F("Subject: ")); - wifiClient.print(messagePrefix); - wifiClient.println(messageContent); - wifiClient.println(); // Required blank line between the header and body - wifiClient.print(messagePrefix); - wifiClient.println(messageContent); - wifiClient.println(F(".")); + ipClient.println(F("From: Security System ")); // Set the sender displayed in the email header + ipClient.println(F("To: Recipient ")); // Set the recipient displayed in the email header + ipClient.print(F("Subject: ")); + ipClient.print(messagePrefix); + ipClient.println(messageContent); + ipClient.println(); // Required blank line between the header and body + ipClient.print(messagePrefix); + ipClient.println(messageContent); + ipClient.println(F(".")); if(!smtpValidResponse()) return false; - wifiClient.println(F("QUIT")); + ipClient.println(F("QUIT")); if(!smtpValidResponse()) return false; - wifiClient.stop(); + ipClient.stop(); return true; } @@ -234,11 +234,11 @@ bool smtpValidResponse() { // Waits for a response unsigned long previousMillis = millis(); - while (!wifiClient.available()) { + while (!ipClient.available()) { dsc.loop(); // Processes Keybus data while waiting on the SMTP response if (millis() - previousMillis > 3000) { Serial.println(F("Connection timed out waiting for a response.")); - wifiClient.stop(); + ipClient.stop(); return false; } yield(); @@ -246,11 +246,11 @@ bool smtpValidResponse() { // Checks the first character of the SMTP reply code - the command was successful if the reply code begins // with "2" or "3" - char replyCode = wifiClient.read(); + char replyCode = ipClient.read(); // Successful, reads the remainder of the response to clear the client buffer if (replyCode == '2' || replyCode == '3') { - while (wifiClient.available()) wifiClient.read(); + while (ipClient.available()) ipClient.read(); return true; } @@ -258,11 +258,11 @@ bool smtpValidResponse() { else { Serial.println(F("Email send error, response:")); Serial.print(replyCode); - while (wifiClient.available()) Serial.print((char)wifiClient.read()); + while (ipClient.available()) Serial.print((char)ipClient.read()); Serial.println(); - wifiClient.println(F("QUIT")); + ipClient.println(F("QUIT")); smtpValidResponse(); - wifiClient.stop(); + ipClient.stop(); return false; } } diff --git a/examples/esp32/HomeAssistant-MQTT/HomeAssistant-MQTT.ino b/examples/esp32/HomeAssistant-MQTT/HomeAssistant-MQTT.ino index eb45c50..f18e4b4 100644 --- a/examples/esp32/HomeAssistant-MQTT/HomeAssistant-MQTT.ino +++ b/examples/esp32/HomeAssistant-MQTT/HomeAssistant-MQTT.ino @@ -200,13 +200,13 @@ const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to w // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 #define dscWritePin 21 // esp32: 4,13,16-33 // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -WiFiClient wifiClient; -PubSubClient mqtt(mqttServer, mqttPort, wifiClient); +WiFiClient ipClient; +PubSubClient mqtt(mqttServer, mqttPort, ipClient); unsigned long mqttPreviousTime; diff --git a/examples/esp32/Homebridge-MQTT/Homebridge-MQTT.ino b/examples/esp32/Homebridge-MQTT/Homebridge-MQTT.ino index bf71139..324c001 100644 --- a/examples/esp32/Homebridge-MQTT/Homebridge-MQTT.ino +++ b/examples/esp32/Homebridge-MQTT/Homebridge-MQTT.ino @@ -199,13 +199,13 @@ const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to w // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 #define dscWritePin 21 // esp32: 4,13,16-33 // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -WiFiClient wifiClient; -PubSubClient mqtt(mqttServer, mqttPort, wifiClient); +WiFiClient ipClient; +PubSubClient mqtt(mqttServer, mqttPort, ipClient); unsigned long mqttPreviousTime; char exitState; diff --git a/examples/esp32/Homey/Homey.ino b/examples/esp32/Homey/Homey.ino index 8e2fe2c..dce044d 100755 --- a/examples/esp32/Homey/Homey.ino +++ b/examples/esp32/Homey/Homey.ino @@ -57,7 +57,7 @@ const char* accessCode = ""; // An access code is required to disarm/night arm // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 #define dscWritePin 21 // esp32: 4,13,16-33 // Initialize components diff --git a/examples/esp32/KeybusReader/KeybusReader.ino b/examples/esp32/KeybusReader/KeybusReader.ino index fcda816..75411fa 100644 --- a/examples/esp32/KeybusReader/KeybusReader.ino +++ b/examples/esp32/KeybusReader/KeybusReader.ino @@ -6,7 +6,8 @@ * to productive use. * * Release notes: - * 1.2 - Show redundant data by default + * 1.2 - Handle spurious data while keybus is disconnected + * Removed redundant data processing * 1.0 - Initial release * * Wiring: @@ -43,7 +44,7 @@ // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 #define dscWritePin 21 // esp32: 4,13,16-33 // Initialize components @@ -75,6 +76,17 @@ void loop() { if (dsc.loop()) { + if (dsc.statusChanged) { // Checks if the security system status has changed + dsc.statusChanged = false; // Reset the status tracking flag + + // Checks if the interface is connected to the Keybus + if (dsc.keybusChanged) { + dsc.keybusChanged = false; // Resets the Keybus data status flag + if (dsc.keybusConnected) Serial.println(F("Keybus connected")); + else Serial.println(F("Keybus disconnected")); + } + } + // If the Keybus data buffer is exceeded, the sketch is too busy to process all Keybus commands. Call // loop() more often, or increase dscBufferSize in the library: src/dscKeybusInterface.h if (dsc.bufferOverflow) { @@ -83,37 +95,37 @@ void loop() { } // Prints panel data - printTimestamp(); - Serial.print(" "); - dsc.printPanelBinary(); // Optionally prints without spaces: printPanelBinary(false); - Serial.print(" ["); - dsc.printPanelCommand(); // Prints the panel command as hex - Serial.print("] "); - dsc.printPanelMessage(); // Prints the decoded message - Serial.println(); - - // Prints keypad and module data when valid panel data is printed - if (dsc.handleModule()) { + if (dsc.keybusConnected) { printTimestamp(); Serial.print(" "); - dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); - Serial.print(" "); - dsc.printModuleMessage(); // Prints the decoded message + dsc.printPanelBinary(); // Optionally prints without spaces: printPanelBinary(false); + Serial.print(" ["); + dsc.printPanelCommand(); // Prints the panel command as hex + Serial.print("] "); + dsc.printPanelMessage(); // Prints the decoded message Serial.println(); + + // Prints keypad and module data when valid panel data is printed + if (dsc.handleModule()) printModule(); } } // Prints keypad and module data when valid panel data is not available - else if (dsc.handleModule()) { - printTimestamp(); - Serial.print(" "); - dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); - Serial.print(" "); - dsc.printModuleMessage(); - Serial.println(); - } + else if (dsc.keybusConnected && dsc.handleModule()) printModule(); } + +// Prints keypad and module data +void printModule() { + printTimestamp(); + Serial.print(" "); + dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); + Serial.print(" "); + dsc.printModuleMessage(); // Prints the decoded message + Serial.println(); +} + + // Prints a timestamp in seconds (with 2 decimal precision) - this is useful to determine when // the panel sends a group of messages immediately after each other due to an event. void printTimestamp() { diff --git a/examples/esp32/OpenHAB-MQTT/OpenHAB-MQTT.ino b/examples/esp32/OpenHAB-MQTT/OpenHAB-MQTT.ino index 5a5c4b5..e53b920 100644 --- a/examples/esp32/OpenHAB-MQTT/OpenHAB-MQTT.ino +++ b/examples/esp32/OpenHAB-MQTT/OpenHAB-MQTT.ino @@ -151,13 +151,13 @@ const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to w // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 #define dscWritePin 21 // esp32: 4,13,16-33 // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -WiFiClient wifiClient; -PubSubClient mqtt(mqttServer, mqttPort, wifiClient); +WiFiClient ipClient; +PubSubClient mqtt(mqttServer, mqttPort, ipClient); unsigned long mqttPreviousTime; diff --git a/examples/esp32/Pushbullet/Pushbullet.ino b/examples/esp32/Pushbullet/Pushbullet.ino index dd11581..73002a1 100644 --- a/examples/esp32/Pushbullet/Pushbullet.ino +++ b/examples/esp32/Pushbullet/Pushbullet.ino @@ -54,7 +54,7 @@ const char* messagePrefix = "[Security system] "; // Set a prefix for all messa // Configures the Keybus interface with the specified pins. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 // HTTPS root certificate for api.pushbullet.com: GlobalSign Root CA - R2, expires 2021.12.15 const char pushbulletCertificateRoot[] = R"=EOF=( @@ -87,7 +87,7 @@ Kk5GkNl1LNj/jO7M3GnrbOYV0KP/SAusVd/fJZ1CtlGjZpVgxdAi5yJ6UaXMhw== // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin); -WiFiClientSecure wifiClient; +WiFiClientSecure ipClient; bool wifiConnected = true; @@ -100,7 +100,7 @@ void setup() { Serial.print(F("WiFi...")); WiFi.mode(WIFI_STA); WiFi.begin(wifiSSID, wifiPassword); - wifiClient.setCACert(pushbulletCertificateRoot); + ipClient.setCACert(pushbulletCertificateRoot); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); @@ -316,47 +316,47 @@ void loop() { bool sendMessage(const char* pushMessage) { // Connects and sends the message as JSON - if (!wifiClient.connect("api.pushbullet.com", 443)) return false; - wifiClient.println(F("POST /v2/pushes HTTP/1.1")); - wifiClient.println(F("Host: api.pushbullet.com")); - wifiClient.println(F("User-Agent: ESP32")); - wifiClient.println(F("Accept: */*")); - wifiClient.println(F("Content-Type: application/json")); - wifiClient.print(F("Content-Length: ")); - wifiClient.println(strlen(pushMessage) + strlen(messagePrefix) + 25); // Length including JSON data - wifiClient.print(F("Access-Token: ")); - wifiClient.println(pushbulletToken); - wifiClient.println(); - wifiClient.print(F("{\"body\":\"")); - wifiClient.print(messagePrefix); - wifiClient.print(pushMessage); - wifiClient.print(F("\",\"type\":\"note\"}")); + if (!ipClient.connect("api.pushbullet.com", 443)) return false; + ipClient.println(F("POST /v2/pushes HTTP/1.1")); + ipClient.println(F("Host: api.pushbullet.com")); + ipClient.println(F("User-Agent: ESP32")); + ipClient.println(F("Accept: */*")); + ipClient.println(F("Content-Type: application/json")); + ipClient.print(F("Content-Length: ")); + ipClient.println(strlen(pushMessage) + strlen(messagePrefix) + 25); // Length including JSON data + ipClient.print(F("Access-Token: ")); + ipClient.println(pushbulletToken); + ipClient.println(); + ipClient.print(F("{\"body\":\"")); + ipClient.print(messagePrefix); + ipClient.print(pushMessage); + ipClient.print(F("\",\"type\":\"note\"}")); // Waits for a response unsigned long previousMillis = millis(); - while (!wifiClient.available()) { + while (!ipClient.available()) { dsc.loop(); if (millis() - previousMillis > 3000) { Serial.println(F("Connection timed out waiting for a response.")); - wifiClient.stop(); + ipClient.stop(); return false; } yield(); } // Reads the response until the first space - the next characters will be the HTTP status code - while (wifiClient.available()) { - if (wifiClient.read() == ' ') break; + while (ipClient.available()) { + if (ipClient.read() == ' ') break; } // Checks the first character of the HTTP status code - the message was sent successfully if the status code // begins with "2" - char statusCode = wifiClient.read(); + char statusCode = ipClient.read(); // Successful, reads the remaining response to clear the client buffer if (statusCode == '2') { - while (wifiClient.available()) wifiClient.read(); - wifiClient.stop(); + while (ipClient.available()) ipClient.read(); + ipClient.stop(); return true; } @@ -364,9 +364,9 @@ bool sendMessage(const char* pushMessage) { else { Serial.println(F("Push notification error, response:")); Serial.print(statusCode); - while (wifiClient.available()) Serial.print((char)wifiClient.read()); + while (ipClient.available()) Serial.print((char)ipClient.read()); Serial.println(); - wifiClient.stop(); + ipClient.stop(); return false; } } diff --git a/examples/esp32/Status/Status.ino b/examples/esp32/Status/Status.ino index a53bc1e..1d23c3b 100644 --- a/examples/esp32/Status/Status.ino +++ b/examples/esp32/Status/Status.ino @@ -43,7 +43,7 @@ // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 #define dscWritePin 21 // esp32: 4,13,16-33 // Initialize components @@ -268,11 +268,14 @@ void loop() { } } - // Checks for a panel timestamp - // - // The panel time can be set using dsc.setTime(year, month, day, hour, minute, "accessCode") - for example: - // dsc.setTime(2015, 10, 21, 7, 28, "1234") # Sets 2015.10.21 07:28 with access code 1234 - // + /* Checks for a panel timestamp + * + * The panel time can be set using dsc.setTime(year, month, day, hour, minute, "accessCode", partition) - the + * partition is optional and defaults to partition 1: + * + * dsc.setTime(2015, 12, 21, 20, 38, "1234") # Sets 2015.12.21 20:38 with access code 1234 + * dsc.setTime(2020, 05, 30, 15, 22, "1234", 2) # Sets 2020.05.30 15:22 with access code 1234 on partition 2 + */ if (dsc.timestampChanged) { dsc.timestampChanged = false; Serial.print(F("Timestamp: ")); diff --git a/examples/esp32/Telegram/Telegram.ino b/examples/esp32/Telegram/Telegram.ino index 36e9f6a..67b04b4 100644 --- a/examples/esp32/Telegram/Telegram.ino +++ b/examples/esp32/Telegram/Telegram.ino @@ -74,13 +74,13 @@ const char* messagePrefix = "[Security system] "; // Set a prefix for all messa // Configures the Keybus interface with the specified pins. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 #define dscWritePin 21 // esp32: 4,13,16-33 // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -WiFiClientSecure wifiClient; -UniversalTelegramBot telegramBot(telegramBotToken, wifiClient); +WiFiClientSecure ipClient; +UniversalTelegramBot telegramBot(telegramBotToken, ipClient); const int telegramCheckInterval = 1000; bool wifiConnected = true; @@ -93,7 +93,7 @@ void setup() { Serial.print(F("WiFi...")); WiFi.mode(WIFI_STA); WiFi.begin(wifiSSID, wifiPassword); - wifiClient.setCACert(TELEGRAM_CERTIFICATE_ROOT); + ipClient.setCACert(TELEGRAM_CERTIFICATE_ROOT); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); diff --git a/examples/esp32/Twilio-SMS/Twilio-SMS.ino b/examples/esp32/Twilio-SMS/Twilio-SMS.ino index 62d0d04..4809f22 100644 --- a/examples/esp32/Twilio-SMS/Twilio-SMS.ino +++ b/examples/esp32/Twilio-SMS/Twilio-SMS.ino @@ -53,11 +53,11 @@ const char* messagePrefix = "[Security system] "; // Set a prefix for all messa // Configures the Keybus interface with the specified pins. #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin); -WiFiClientSecure wifiClient; +WiFiClientSecure ipClient; bool wifiConnected = true; @@ -274,53 +274,53 @@ void loop() { bool sendMessage(const char* messageContent) { // Connects and sends the message as x-www-form-urlencoded - if (!wifiClient.connect("api.twilio.com", 443)) return false; - wifiClient.print(F("POST https://api.twilio.com/2010-04-01/Accounts/")); - wifiClient.print(AccountSID); - wifiClient.println(F("/Messages.json HTTP/1.1")); - wifiClient.print(F("Authorization: Basic ")); - wifiClient.println(Base64EncodedAuth); - wifiClient.println(F("Host: api.twilio.com")); - wifiClient.println(F("User-Agent: ESP32")); - wifiClient.println(F("Accept: */*")); - wifiClient.println(F("Content-Type: application/x-www-form-urlencoded")); - wifiClient.print(F("Content-Length: ")); - wifiClient.println(strlen(To) + strlen(From) + strlen(messagePrefix) + strlen(messageContent) + 18); // Length including data - wifiClient.println("Connection: Close"); - wifiClient.println(); - wifiClient.print(F("To=+")); - wifiClient.print(To); - wifiClient.print(F("&From=+")); - wifiClient.print(From); - wifiClient.print(F("&Body=")); - wifiClient.print(messagePrefix); - wifiClient.println(messageContent); + if (!ipClient.connect("api.twilio.com", 443)) return false; + ipClient.print(F("POST https://api.twilio.com/2010-04-01/Accounts/")); + ipClient.print(AccountSID); + ipClient.println(F("/Messages.json HTTP/1.1")); + ipClient.print(F("Authorization: Basic ")); + ipClient.println(Base64EncodedAuth); + ipClient.println(F("Host: api.twilio.com")); + ipClient.println(F("User-Agent: ESP32")); + ipClient.println(F("Accept: */*")); + ipClient.println(F("Content-Type: application/x-www-form-urlencoded")); + ipClient.print(F("Content-Length: ")); + ipClient.println(strlen(To) + strlen(From) + strlen(messagePrefix) + strlen(messageContent) + 18); // Length including data + ipClient.println("Connection: Close"); + ipClient.println(); + ipClient.print(F("To=+")); + ipClient.print(To); + ipClient.print(F("&From=+")); + ipClient.print(From); + ipClient.print(F("&Body=")); + ipClient.print(messagePrefix); + ipClient.println(messageContent); // Waits for a response unsigned long previousMillis = millis(); - while (!wifiClient.available()) { + while (!ipClient.available()) { dsc.loop(); if (millis() - previousMillis > 3000) { Serial.println(F("Connection timed out waiting for a response.")); - wifiClient.stop(); + ipClient.stop(); return false; } yield(); } // Reads the response until the first space - the next characters will be the HTTP status code - while (wifiClient.available()) { - if (wifiClient.read() == ' ') break; + while (ipClient.available()) { + if (ipClient.read() == ' ') break; } // Checks the first character of the HTTP status code - the message was sent successfully if the status code // begins with "2" - char statusCode = wifiClient.read(); + char statusCode = ipClient.read(); // Successful, reads the remaining response to clear the client buffer if (statusCode == '2') { - while (wifiClient.available()) wifiClient.read(); - wifiClient.stop(); + while (ipClient.available()) ipClient.read(); + ipClient.stop(); return true; } @@ -328,9 +328,9 @@ bool sendMessage(const char* messageContent) { else { Serial.println(F("SMS messaging error, response:")); Serial.print(statusCode); - while (wifiClient.available()) Serial.print((char)wifiClient.read()); + while (ipClient.available()) Serial.print((char)ipClient.read()); Serial.println(); - wifiClient.stop(); + ipClient.stop(); return false; } } diff --git a/examples/esp32/Unlocker/Unlocker.ino b/examples/esp32/Unlocker/Unlocker.ino index 4e8b9c7..afd183c 100644 --- a/examples/esp32/Unlocker/Unlocker.ino +++ b/examples/esp32/Unlocker/Unlocker.ino @@ -85,7 +85,7 @@ // Configures the Keybus interface with the specified pins #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 #define dscWritePin 21 // esp32: 4,13,16-33 #define dscRelayPin 17 // esp32: 4,13,16-33 - Optional, leave this pin disconnected if not using a relay diff --git a/examples/esp32/VirtualKeypad-Blynk/VirtualKeypad-Blynk.ino b/examples/esp32/VirtualKeypad-Blynk/VirtualKeypad-Blynk.ino index a11cdfb..32d3102 100644 --- a/examples/esp32/VirtualKeypad-Blynk/VirtualKeypad-Blynk.ino +++ b/examples/esp32/VirtualKeypad-Blynk/VirtualKeypad-Blynk.ino @@ -86,7 +86,7 @@ int blynkPort = 8080; // Blynk local server port // Configures the Keybus interface with the specified pins - dscWritePin is // optional, leaving it out disables the virtual keypad #define dscClockPin 18 // esp32: 4,13,16-39 -#define dscReadPin 19 // esp32: 4,13,16-39 +#define dscReadPin 19 // esp32: 4,13,16-39 #define dscWritePin 21 // esp32: 4,13,16-33 // Initialize components diff --git a/examples/esp8266/Email/Email.ino b/examples/esp8266/Email/Email.ino index e55c667..8dfb38c 100644 --- a/examples/esp8266/Email/Email.ino +++ b/examples/esp8266/Email/Email.ino @@ -55,11 +55,11 @@ const char* messagePrefix = "[Security system] "; // Set a prefix for all messa // Configures the Keybus interface with the specified pins. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin); -WiFiClientSecure wifiClient; +WiFiClientSecure ipClient; bool wifiConnected = true; @@ -78,7 +78,7 @@ void setup() { } Serial.print(F("connected: ")); Serial.println(WiFi.localIP()); - wifiClient.setInsecure(); + ipClient.setInsecure(); // Sends a message on startup to verify connectivity Serial.print(F("Email....")); @@ -201,37 +201,37 @@ void loop() { // server - the login and password must be base64 encoded. For example, on the macOS/Linux terminal: // $ echo -n 'mylogin@example.com' | base64 -w 0 bool sendMessage(const char* messageContent) { - if (!wifiClient.connect("smtp.example.com", 465)) return false; // Set the SMTP server address - for example: smtp.gmail.com + if (!ipClient.connect("smtp.example.com", 465)) return false; // Set the SMTP server address - for example: smtp.gmail.com if(!smtpValidResponse()) return false; - wifiClient.println(F("HELO ESP8266")); + ipClient.println(F("HELO ESP8266")); if(!smtpValidResponse()) return false; - wifiClient.println(F("AUTH LOGIN")); + ipClient.println(F("AUTH LOGIN")); if(!smtpValidResponse()) return false; - wifiClient.println(F("myBase64encodedLogin")); // Set the SMTP server login in base64 + ipClient.println(F("myBase64encodedLogin")); // Set the SMTP server login in base64 if(!smtpValidResponse()) return false; - wifiClient.println(F("myBase64encodedPassword")); // Set the SMTP server password in base64 + ipClient.println(F("myBase64encodedPassword")); // Set the SMTP server password in base64 if(!smtpValidResponse()) return false; - wifiClient.println(F("MAIL FROM:")); // Set the sender address + ipClient.println(F("MAIL FROM:")); // Set the sender address if(!smtpValidResponse()) return false; - wifiClient.println(F("RCPT TO:")); // Set the recipient address - repeat to add multiple recipients + ipClient.println(F("RCPT TO:")); // Set the recipient address - repeat to add multiple recipients if(!smtpValidResponse()) return false; - wifiClient.println(F("RCPT TO:")); // An optional additional recipient + ipClient.println(F("RCPT TO:")); // An optional additional recipient if(!smtpValidResponse()) return false; - wifiClient.println(F("DATA")); + ipClient.println(F("DATA")); if(!smtpValidResponse()) return false; - wifiClient.println(F("From: Security System ")); // Set the sender displayed in the email header - wifiClient.println(F("To: Recipient ")); // Set the recipient displayed in the email header - wifiClient.print(F("Subject: ")); - wifiClient.print(messagePrefix); - wifiClient.println(messageContent); - wifiClient.println(); // Required blank line between the header and body - wifiClient.print(messagePrefix); - wifiClient.println(messageContent); - wifiClient.println(F(".")); + ipClient.println(F("From: Security System ")); // Set the sender displayed in the email header + ipClient.println(F("To: Recipient ")); // Set the recipient displayed in the email header + ipClient.print(F("Subject: ")); + ipClient.print(messagePrefix); + ipClient.println(messageContent); + ipClient.println(); // Required blank line between the header and body + ipClient.print(messagePrefix); + ipClient.println(messageContent); + ipClient.println(F(".")); if(!smtpValidResponse()) return false; - wifiClient.println(F("QUIT")); + ipClient.println(F("QUIT")); if(!smtpValidResponse()) return false; - wifiClient.stop(); + ipClient.stop(); return true; } @@ -240,11 +240,11 @@ bool smtpValidResponse() { // Waits for a response unsigned long previousMillis = millis(); - while (!wifiClient.available()) { + while (!ipClient.available()) { dsc.loop(); // Processes Keybus data while waiting on the SMTP response if (millis() - previousMillis > 3000) { Serial.println(F("Connection timed out waiting for a response.")); - wifiClient.stop(); + ipClient.stop(); return false; } yield(); @@ -252,11 +252,11 @@ bool smtpValidResponse() { // Checks the first character of the SMTP reply code - the command was successful if the reply code begins // with "2" or "3" - char replyCode = wifiClient.read(); + char replyCode = ipClient.read(); // Successful, reads the remainder of the response to clear the client buffer if (replyCode == '2' || replyCode == '3') { - while (wifiClient.available()) wifiClient.read(); + while (ipClient.available()) ipClient.read(); return true; } @@ -264,11 +264,11 @@ bool smtpValidResponse() { else { Serial.println(F("Email send error, response:")); Serial.print(replyCode); - while (wifiClient.available()) Serial.print((char)wifiClient.read()); + while (ipClient.available()) Serial.print((char)ipClient.read()); Serial.println(); - wifiClient.println(F("QUIT")); + ipClient.println(F("QUIT")); smtpValidResponse(); - wifiClient.stop(); + ipClient.stop(); return false; } } diff --git a/examples/esp8266/HomeAssistant-MQTT/HomeAssistant-MQTT.ino b/examples/esp8266/HomeAssistant-MQTT/HomeAssistant-MQTT.ino index 753725f..8db528a 100644 --- a/examples/esp8266/HomeAssistant-MQTT/HomeAssistant-MQTT.ino +++ b/examples/esp8266/HomeAssistant-MQTT/HomeAssistant-MQTT.ino @@ -208,13 +208,13 @@ const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to w // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -WiFiClient wifiClient; -PubSubClient mqtt(mqttServer, mqttPort, wifiClient); +WiFiClient ipClient; +PubSubClient mqtt(mqttServer, mqttPort, ipClient); unsigned long mqttPreviousTime; diff --git a/examples/esp8266/Homebridge-MQTT/Homebridge-MQTT.ino b/examples/esp8266/Homebridge-MQTT/Homebridge-MQTT.ino index 181ca63..a2bba6a 100644 --- a/examples/esp8266/Homebridge-MQTT/Homebridge-MQTT.ino +++ b/examples/esp8266/Homebridge-MQTT/Homebridge-MQTT.ino @@ -205,13 +205,13 @@ const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to w // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -WiFiClient wifiClient; -PubSubClient mqtt(mqttServer, mqttPort, wifiClient); +WiFiClient ipClient; +PubSubClient mqtt(mqttServer, mqttPort, ipClient); unsigned long mqttPreviousTime; char exitState; diff --git a/examples/esp8266/Homey/Homey.ino b/examples/esp8266/Homey/Homey.ino index 45999f1..a0e4b1d 100755 --- a/examples/esp8266/Homey/Homey.ino +++ b/examples/esp8266/Homey/Homey.ino @@ -60,7 +60,7 @@ const char* accessCode = ""; // An access code is required to disarm/night arm // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components diff --git a/examples/esp8266/KeybusReader/KeybusReader.ino b/examples/esp8266/KeybusReader/KeybusReader.ino index bc074b0..874c4af 100644 --- a/examples/esp8266/KeybusReader/KeybusReader.ino +++ b/examples/esp8266/KeybusReader/KeybusReader.ino @@ -6,7 +6,8 @@ * to productive use. * * Release notes: - * 1.2 - Show redundant data by default + * 1.2 - Handle spurious data while keybus is disconnected + * Removed redundant data processing * 1.1 - Updated esp8266 wiring diagram for 33k/10k resistors * 1.0 - Initial release * @@ -44,7 +45,7 @@ // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components @@ -76,6 +77,17 @@ void loop() { if (dsc.loop()) { + if (dsc.statusChanged) { // Checks if the security system status has changed + dsc.statusChanged = false; // Reset the status tracking flag + + // Checks if the interface is connected to the Keybus + if (dsc.keybusChanged) { + dsc.keybusChanged = false; // Resets the Keybus data status flag + if (dsc.keybusConnected) Serial.println(F("Keybus connected")); + else Serial.println(F("Keybus disconnected")); + } + } + // If the Keybus data buffer is exceeded, the sketch is too busy to process all Keybus commands. Call // loop() more often, or increase dscBufferSize in the library: src/dscKeybusInterface.h if (dsc.bufferOverflow) { @@ -84,37 +96,37 @@ void loop() { } // Prints panel data - printTimestamp(); - Serial.print(" "); - dsc.printPanelBinary(); // Optionally prints without spaces: printPanelBinary(false); - Serial.print(" ["); - dsc.printPanelCommand(); // Prints the panel command as hex - Serial.print("] "); - dsc.printPanelMessage(); // Prints the decoded message - Serial.println(); - - // Prints keypad and module data when valid panel data is printed - if (dsc.handleModule()) { + if (dsc.keybusConnected) { printTimestamp(); Serial.print(" "); - dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); - Serial.print(" "); - dsc.printModuleMessage(); // Prints the decoded message + dsc.printPanelBinary(); // Optionally prints without spaces: printPanelBinary(false); + Serial.print(" ["); + dsc.printPanelCommand(); // Prints the panel command as hex + Serial.print("] "); + dsc.printPanelMessage(); // Prints the decoded message Serial.println(); + + // Prints keypad and module data when valid panel data is printed + if (dsc.handleModule()) printModule(); } } // Prints keypad and module data when valid panel data is not available - else if (dsc.handleModule()) { - printTimestamp(); - Serial.print(" "); - dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); - Serial.print(" "); - dsc.printModuleMessage(); - Serial.println(); - } + else if (dsc.keybusConnected && dsc.handleModule()) printModule(); } + +// Prints keypad and module data +void printModule() { + printTimestamp(); + Serial.print(" "); + dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); + Serial.print(" "); + dsc.printModuleMessage(); // Prints the decoded message + Serial.println(); +} + + // Prints a timestamp in seconds (with 2 decimal precision) - this is useful to determine when // the panel sends a group of messages immediately after each other due to an event. void printTimestamp() { diff --git a/examples/esp8266/KeybusReaderIP/KeybusReaderIP.ino b/examples/esp8266/KeybusReaderIP/KeybusReaderIP.ino index d5c7510..b86e9a4 100644 --- a/examples/esp8266/KeybusReaderIP/KeybusReaderIP.ino +++ b/examples/esp8266/KeybusReaderIP/KeybusReaderIP.ino @@ -6,10 +6,12 @@ * * Usage: * 1. Set WiFi settings and upload the sketch. - * 2. For macOS/Linux, use netcat to connect: nc dsc.local 80 + * 2. For macOS/Linux: telnet dsc.local * * Release notes: - * 1.2 - Show redundant data by default + * 1.2 - Updated to connect via telnet + * Handle spurious data while keybus is disconnected + * Removed redundant data processing * 1.1 - Updated esp8266 wiring diagram for 33k/10k resistors * 1.0 - Initial release * @@ -51,20 +53,19 @@ // Settings const char* wifiSSID = ""; const char* wifiPassword = ""; -char dnsHostname[] = "dsc"; // Sets the domain name - if set to "dsc", access via: http://dsc.local -int serverPort = 80; +char dnsHostname[] = "dsc"; // Sets the domain name - if set to "dsc", access via: dsc.local +int serverPort = 23; // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -WiFiServer wifiServer(serverPort); -WiFiClient client; -bool newClient = true; +WiFiServer ipServer(serverPort); +WiFiClient ipClient; void setup() { @@ -90,7 +91,7 @@ void setup() { } } - wifiServer.begin(); + ipServer.begin(); Serial.print(F("Server started: ")); Serial.print(dnsHostname); Serial.print(F(".local:")); @@ -103,7 +104,7 @@ 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), begin(client) for IP. - dsc.begin(client); + dsc.begin(ipClient); Serial.println(F("DSC Keybus Interface is online.")); } @@ -114,80 +115,94 @@ void loop() { dsc.loop(); //call it to process buffer when client is disconnected - client = wifiServer.available(); - if (client) { + // Checks if the interface is connected to the Keybus + if (dsc.keybusChanged) { + dsc.keybusChanged = false; // Resets the Keybus data status flag + if (dsc.keybusConnected) Serial.println(F("Keybus connected")); + else Serial.println(F("Keybus disconnected")); + } + + ipClient = ipServer.available(); + if (ipClient) { + static bool newClient = true; - while (client.connected()) { + while (ipClient.connected()) { // Once client is connected, tell it is connected (once!) if (newClient) { Serial.println("Client connected"); - client.printf("Connected to dscKeybusReader\n"); + ipClient.printf("Connected to DSC Keybus Reader\r\n"); newClient = false; } // Reads from IP input and writes to the Keybus as a virtual keypad - while (client.available() > 0) { - char c = static_cast(client.read()); - dsc.write(c); - yield(); + if (ipClient.available() > 0) { + if (ipClient.peek() == 0xFF) { // Checks for Telnet options negotiation data + for (byte i = 0; i < 3; i++) ipClient.read(); + } else { + char c = static_cast(ipClient.read()); + dsc.write(c); + } } if (dsc.loop()) { + // If the Keybus data buffer is exceeded, the sketch is too busy to process all Keybus commands. Call // loop more often, or increase dscBufferSize in the library: src/dscKeybusInterface.h if (dsc.bufferOverflow) { - client.print(F("Keybus buffer overflow")); + ipClient.print(F("Keybus buffer overflow")); dsc.bufferOverflow = false; } // Prints panel data - printTimestamp(); - client.print(" "); - dsc.printPanelBinary(); // Optionally prints without spaces: printPanelBinary(false); - client.print(" ["); - dsc.printPanelCommand(); // Prints the panel command as hex - client.print("] "); - dsc.printPanelMessage(); // Prints the decoded message - client.printf("\n"); - - // Prints keypad and module data when valid panel data is printed - if (dsc.handleModule()) { + if (dsc.keybusConnected) { printTimestamp(); - client.print(" "); - dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); - client.print(" "); - dsc.printModuleMessage(); // Prints the decoded message - client.printf("\n"); + ipClient.print(" "); + dsc.printPanelBinary(); // Optionally prints without spaces: printPanelBinary(false); + ipClient.print(" ["); + dsc.printPanelCommand(); // Prints the panel command as hex + ipClient.print("] "); + dsc.printPanelMessage(); // Prints the decoded message + ipClient.printf("\r\n"); } + + // Prints keypad and module data when valid panel data is printed + if (dsc.handleModule()) printModule(); } // Prints keypad and module data when valid panel data is not available - else if (dsc.handleModule()) { - printTimestamp(); - client.print(" "); - dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); - client.print(" "); - dsc.printModuleMessage(); - client.printf("\n"); - } + else if (dsc.keybusConnected && dsc.handleModule()) printModule(); MDNS.update(); + yield(); } - client.stop(); + + ipClient.stop(); newClient = true; Serial.println("Client disconnected"); } } + +// Prints keypad and module data +void printModule() { + printTimestamp(); + ipClient.print(" "); + dsc.printModuleBinary(); // Optionally prints without spaces: printKeybusBinary(false); + ipClient.print(" "); + dsc.printModuleMessage(); + ipClient.printf("\r\n"); +} + + // Prints a timestamp in seconds (with 2 decimal precision) - this is useful to determine when // the panel sends a group of messages immediately after each other due to an event. void printTimestamp() { float timeStamp = millis() / 1000.0; - if (timeStamp < 10) client.print(" "); - else if (timeStamp < 100) client.print(" "); - else if (timeStamp < 1000) client.print(" "); - else if (timeStamp < 10000) client.print(" "); - client.print(timeStamp, 2); - client.print(F(":")); + if (timeStamp < 10) ipClient.print(" "); + else if (timeStamp < 100) ipClient.print(" "); + else if (timeStamp < 1000) ipClient.print(" "); + else if (timeStamp < 10000) ipClient.print(" "); + ipClient.print(timeStamp, 2); + ipClient.print(F(":")); } diff --git a/examples/esp8266/OpenHAB-MQTT/OpenHAB-MQTT.ino b/examples/esp8266/OpenHAB-MQTT/OpenHAB-MQTT.ino index 7607c7d..8caca4e 100644 --- a/examples/esp8266/OpenHAB-MQTT/OpenHAB-MQTT.ino +++ b/examples/esp8266/OpenHAB-MQTT/OpenHAB-MQTT.ino @@ -152,13 +152,13 @@ const char* mqttSubscribeTopic = "dsc/Set"; // Receives messages to w // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); -WiFiClient wifiClient; -PubSubClient mqtt(mqttServer, mqttPort, wifiClient); +WiFiClient ipClient; +PubSubClient mqtt(mqttServer, mqttPort, ipClient); unsigned long mqttPreviousTime; diff --git a/examples/esp8266/Pushbullet/Pushbullet.ino b/examples/esp8266/Pushbullet/Pushbullet.ino index 4459242..7c2fc13 100644 --- a/examples/esp8266/Pushbullet/Pushbullet.ino +++ b/examples/esp8266/Pushbullet/Pushbullet.ino @@ -60,7 +60,7 @@ const char* messagePrefix = "[Security system] "; // Set a prefix for all messa // Configures the Keybus interface with the specified pins. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // HTTPS root certificate for api.pushbullet.com: GlobalSign Root CA - R2, expires 2021.12.15 const char pushbulletCertificateRoot[] = R"=EOF=( @@ -94,7 +94,7 @@ Kk5GkNl1LNj/jO7M3GnrbOYV0KP/SAusVd/fJZ1CtlGjZpVgxdAi5yJ6UaXMhw== // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin); X509List pushbulletCert(pushbulletCertificateRoot); -WiFiClientSecure wifiClient; +WiFiClientSecure ipClient; bool wifiConnected = true; @@ -107,7 +107,7 @@ void setup() { Serial.print(F("WiFi")); WiFi.mode(WIFI_STA); WiFi.begin(wifiSSID, wifiPassword); - wifiClient.setTrustAnchors(&pushbulletCert); + ipClient.setTrustAnchors(&pushbulletCert); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); @@ -323,47 +323,47 @@ void loop() { bool sendMessage(const char* messageContent) { // Connects and sends the message as a Pushbullet note-type push - if (!wifiClient.connect("api.pushbullet.com", 443)) return false; - wifiClient.println(F("POST /v2/pushes HTTP/1.1")); - wifiClient.println(F("Host: api.pushbullet.com")); - wifiClient.println(F("User-Agent: ESP8266")); - wifiClient.println(F("Accept: */*")); - wifiClient.println(F("Content-Type: application/json")); - wifiClient.print(F("Content-Length: ")); - wifiClient.println(strlen(messageContent) + strlen(messagePrefix) + 25); // Length including JSON data - wifiClient.print(F("Access-Token: ")); - wifiClient.println(pushbulletToken); - wifiClient.println(); - wifiClient.print(F("{\"body\":\"")); - wifiClient.print(messagePrefix); - wifiClient.print(messageContent); - wifiClient.print(F("\",\"type\":\"note\"}")); + if (!ipClient.connect("api.pushbullet.com", 443)) return false; + ipClient.println(F("POST /v2/pushes HTTP/1.1")); + ipClient.println(F("Host: api.pushbullet.com")); + ipClient.println(F("User-Agent: ESP8266")); + ipClient.println(F("Accept: */*")); + ipClient.println(F("Content-Type: application/json")); + ipClient.print(F("Content-Length: ")); + ipClient.println(strlen(messageContent) + strlen(messagePrefix) + 25); // Length including JSON data + ipClient.print(F("Access-Token: ")); + ipClient.println(pushbulletToken); + ipClient.println(); + ipClient.print(F("{\"body\":\"")); + ipClient.print(messagePrefix); + ipClient.print(messageContent); + ipClient.print(F("\",\"type\":\"note\"}")); // Waits for a response unsigned long previousMillis = millis(); - while (!wifiClient.available()) { + while (!ipClient.available()) { dsc.loop(); if (millis() - previousMillis > 3000) { Serial.println(F("Connection timed out waiting for a response.")); - wifiClient.stop(); + ipClient.stop(); return false; } yield(); } // Reads the response until the first space - the next characters will be the HTTP status code - while (wifiClient.available()) { - if (wifiClient.read() == ' ') break; + while (ipClient.available()) { + if (ipClient.read() == ' ') break; } // Checks the first character of the HTTP status code - the message was sent successfully if the status code // begins with "2" - char statusCode = wifiClient.read(); + char statusCode = ipClient.read(); // Successful, reads the remaining response to clear the client buffer if (statusCode == '2') { - while (wifiClient.available()) wifiClient.read(); - wifiClient.stop(); + while (ipClient.available()) ipClient.read(); + ipClient.stop(); return true; } @@ -371,9 +371,9 @@ bool sendMessage(const char* messageContent) { else { Serial.println(F("Push notification error, response:")); Serial.print(statusCode); - while (wifiClient.available()) Serial.print((char)wifiClient.read()); + while (ipClient.available()) Serial.print((char)ipClient.read()); Serial.println(); - wifiClient.stop(); + ipClient.stop(); return false; } } diff --git a/examples/esp8266/Status/Status.ino b/examples/esp8266/Status/Status.ino index e4c162f..1f59621 100644 --- a/examples/esp8266/Status/Status.ino +++ b/examples/esp8266/Status/Status.ino @@ -45,7 +45,7 @@ // Configures the Keybus interface with the specified pins - dscWritePin is optional, leaving it out disables the // virtual keypad. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components @@ -270,11 +270,14 @@ void loop() { } } - // Checks for a panel timestamp - // - // The panel time can be set using dsc.setTime(year, month, day, hour, minute, "accessCode") - for example: - // dsc.setTime(2015, 10, 21, 7, 28, "1234") # Sets 2015.10.21 07:28 with access code 1234 - // + /* Checks for a panel timestamp + * + * The panel time can be set using dsc.setTime(year, month, day, hour, minute, "accessCode", partition) - the + * partition is optional and defaults to partition 1: + * + * dsc.setTime(2015, 12, 21, 20, 38, "1234") # Sets 2015.12.21 20:38 with access code 1234 + * dsc.setTime(2020, 05, 30, 15, 22, "1234", 2) # Sets 2020.05.30 15:22 with access code 1234 on partition 2 + */ if (dsc.timestampChanged) { dsc.timestampChanged = false; Serial.print(F("Timestamp: ")); diff --git a/examples/esp8266/Telegram/Telegram.ino b/examples/esp8266/Telegram/Telegram.ino index 47a7ac0..1acedc5 100644 --- a/examples/esp8266/Telegram/Telegram.ino +++ b/examples/esp8266/Telegram/Telegram.ino @@ -74,14 +74,14 @@ const char* messagePrefix = "[Security system] "; // Set a prefix for all messa // Configures the Keybus interface with the specified pins. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin, dscWritePin); X509List telegramCert(TELEGRAM_CERTIFICATE_ROOT); -WiFiClientSecure wifiClient; -UniversalTelegramBot telegramBot(telegramBotToken, wifiClient); +WiFiClientSecure ipClient; +UniversalTelegramBot telegramBot(telegramBotToken, ipClient); const int telegramCheckInterval = 1000; bool wifiConnected = true; @@ -95,7 +95,7 @@ void setup() { Serial.print(F("WiFi")); WiFi.mode(WIFI_STA); WiFi.begin(wifiSSID, wifiPassword); - wifiClient.setTrustAnchors(&telegramCert); + ipClient.setTrustAnchors(&telegramCert); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); diff --git a/examples/esp8266/Twilio-SMS/Twilio-SMS.ino b/examples/esp8266/Twilio-SMS/Twilio-SMS.ino index 572efe2..ebd67c7 100644 --- a/examples/esp8266/Twilio-SMS/Twilio-SMS.ino +++ b/examples/esp8266/Twilio-SMS/Twilio-SMS.ino @@ -59,11 +59,11 @@ const char* messagePrefix = "[Security system] "; // Set a prefix for all messa // Configures the Keybus interface with the specified pins. #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components dscKeybusInterface dsc(dscClockPin, dscReadPin); -WiFiClientSecure wifiClient; +WiFiClientSecure ipClient; bool wifiConnected = true; @@ -82,7 +82,7 @@ void setup() { } Serial.print(F("connected: ")); Serial.println(WiFi.localIP()); - wifiClient.setInsecure(); + ipClient.setInsecure(); // Sends a message on startup to verify connectivity Serial.print(F("Twilio....")); @@ -281,53 +281,53 @@ void loop() { bool sendMessage(const char* messageContent) { // Connects and sends the message as x-www-form-urlencoded - if (!wifiClient.connect("api.twilio.com", 443)) return false; - wifiClient.print(F("POST https://api.twilio.com/2010-04-01/Accounts/")); - wifiClient.print(AccountSID); - wifiClient.println(F("/Messages.json HTTP/1.1")); - wifiClient.print(F("Authorization: Basic ")); - wifiClient.println(Base64EncodedAuth); - wifiClient.println(F("Host: api.twilio.com")); - wifiClient.println(F("User-Agent: ESP8266")); - wifiClient.println(F("Accept: */*")); - wifiClient.println(F("Content-Type: application/x-www-form-urlencoded")); - wifiClient.print(F("Content-Length: ")); - wifiClient.println(strlen(To) + strlen(From) + strlen(messagePrefix) + strlen(messageContent) + 18); // Length including data - wifiClient.println("Connection: Close"); - wifiClient.println(); - wifiClient.print(F("To=+")); - wifiClient.print(To); - wifiClient.print(F("&From=+")); - wifiClient.print(From); - wifiClient.print(F("&Body=")); - wifiClient.print(messagePrefix); - wifiClient.println(messageContent); + if (!ipClient.connect("api.twilio.com", 443)) return false; + ipClient.print(F("POST https://api.twilio.com/2010-04-01/Accounts/")); + ipClient.print(AccountSID); + ipClient.println(F("/Messages.json HTTP/1.1")); + ipClient.print(F("Authorization: Basic ")); + ipClient.println(Base64EncodedAuth); + ipClient.println(F("Host: api.twilio.com")); + ipClient.println(F("User-Agent: ESP8266")); + ipClient.println(F("Accept: */*")); + ipClient.println(F("Content-Type: application/x-www-form-urlencoded")); + ipClient.print(F("Content-Length: ")); + ipClient.println(strlen(To) + strlen(From) + strlen(messagePrefix) + strlen(messageContent) + 18); // Length including data + ipClient.println("Connection: Close"); + ipClient.println(); + ipClient.print(F("To=+")); + ipClient.print(To); + ipClient.print(F("&From=+")); + ipClient.print(From); + ipClient.print(F("&Body=")); + ipClient.print(messagePrefix); + ipClient.println(messageContent); // Waits for a response unsigned long previousMillis = millis(); - while (!wifiClient.available()) { + while (!ipClient.available()) { dsc.loop(); if (millis() - previousMillis > 3000) { Serial.println(F("Connection timed out waiting for a response.")); - wifiClient.stop(); + ipClient.stop(); return false; } yield(); } // Reads the response until the first space - the next characters will be the HTTP status code - while (wifiClient.available()) { - if (wifiClient.read() == ' ') break; + while (ipClient.available()) { + if (ipClient.read() == ' ') break; } // Checks the first character of the HTTP status code - the message was sent successfully if the status code // begins with "2" - char statusCode = wifiClient.read(); + char statusCode = ipClient.read(); // Successful, reads the remaining response to clear the client buffer if (statusCode == '2') { - while (wifiClient.available()) wifiClient.read(); - wifiClient.stop(); + while (ipClient.available()) ipClient.read(); + ipClient.stop(); return true; } @@ -335,9 +335,9 @@ bool sendMessage(const char* messageContent) { else { Serial.println(F("SMS messaging error, response:")); Serial.print(statusCode); - while (wifiClient.available()) Serial.print((char)wifiClient.read()); + while (ipClient.available()) Serial.print((char)ipClient.read()); Serial.println(); - wifiClient.stop(); + ipClient.stop(); return false; } } diff --git a/examples/esp8266/Unlocker/Unlocker.ino b/examples/esp8266/Unlocker/Unlocker.ino index 243946e..e34a580 100644 --- a/examples/esp8266/Unlocker/Unlocker.ino +++ b/examples/esp8266/Unlocker/Unlocker.ino @@ -91,7 +91,7 @@ // Configures the Keybus interface with the specified pins #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscRelayPin D6 // esp8266: D5, D6, D7 (GPIO 14, 12, 13) - Optional, leave this pin disconnected if not using a relay diff --git a/examples/esp8266/VirtualKeypad-Blynk/VirtualKeypad-Blynk.ino b/examples/esp8266/VirtualKeypad-Blynk/VirtualKeypad-Blynk.ino index d4f0e8e..f5a8fca 100644 --- a/examples/esp8266/VirtualKeypad-Blynk/VirtualKeypad-Blynk.ino +++ b/examples/esp8266/VirtualKeypad-Blynk/VirtualKeypad-Blynk.ino @@ -87,7 +87,7 @@ int blynkPort = 8080; // Blynk local server port // Configures the Keybus interface with the specified pins - dscWritePin is // optional, leaving it out disables the virtual keypad #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components diff --git a/examples/esp8266/VirtualKeypad-Web/VirtualKeypad-Web.ino b/examples/esp8266/VirtualKeypad-Web/VirtualKeypad-Web.ino index f4664be..46e428a 100644 --- a/examples/esp8266/VirtualKeypad-Web/VirtualKeypad-Web.ino +++ b/examples/esp8266/VirtualKeypad-Web/VirtualKeypad-Web.ino @@ -77,7 +77,7 @@ char dnsHostname[] = "dsc"; // Sets the host name - if set to "dsc", access via // Configures the Keybus interface with the specified pins - dscWritePin is // optional, leaving it out disables the virtual keypad #define dscClockPin D1 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) -#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) +#define dscReadPin D2 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) #define dscWritePin D8 // esp8266: D1, D2, D8 (GPIO 5, 4, 15) // Initialize components diff --git a/src/dscKeybusInterface.cpp b/src/dscKeybusInterface.cpp index beaea38..7af24ca 100644 --- a/src/dscKeybusInterface.cpp +++ b/src/dscKeybusInterface.cpp @@ -206,13 +206,15 @@ bool dscKeybusInterface::loop() { #endif // Waits at startup for the 0x05 status command or a command with valid CRC data to eliminate spurious data. - static bool firstClockCycle = true; - if (firstClockCycle) { - if ((validCRC() || panelData[0] == 0x05) && panelData[0] != 0) { - firstClockCycle = false; + static bool startupCycle = true; + if (startupCycle) { + if (panelData[0] == 0) return false; + else if (panelData[0] == 0x05) { + if (panelByteCount == 6) firstGen = true; + startupCycle = false; writeReady = true; } - else return false; + else if (!validCRC()) return false; } // Sets writeReady status @@ -262,7 +264,7 @@ bool dscKeybusInterface::loop() { } -// Deprecated, relabeled to loop() +// Deprecated, replaced by loop() bool dscKeybusInterface::handlePanel() { // Checks if Keybus data is detected and sets a status flag if data is not detected for 3s diff --git a/src/dscKeybusInterface.h b/src/dscKeybusInterface.h index c984bc3..ee6204a 100644 --- a/src/dscKeybusInterface.h +++ b/src/dscKeybusInterface.h @@ -89,7 +89,7 @@ class dscKeybusInterface { int year; // Sets panel time, the year can be sent as either 2 or 4 digits, returns true if the panel is ready to set the time - bool setTime(unsigned int year, byte month, byte day, byte hour, byte minute, const char* accessCode); + bool setTime(unsigned int year, byte month, byte day, byte hour, byte minute, const char* accessCode, byte timePartition = 1); // Status tracking bool statusChanged; // True after any status change @@ -304,6 +304,7 @@ class dscKeybusInterface { bool previousFire[dscPartitions]; byte previousOpenZones[dscZones], previousAlarmZones[dscZones]; byte previousPgmOutputs[2]; + bool firstGen; static byte dscClockPin; static byte dscReadPin; diff --git a/src/dscKeybusPrintData.cpp b/src/dscKeybusPrintData.cpp index aa59ebc..2dc0d3b 100644 --- a/src/dscKeybusPrintData.cpp +++ b/src/dscKeybusPrintData.cpp @@ -817,7 +817,7 @@ void dscKeybusInterface::printPanelStatus3(byte panelByte) { /* * Zone expander trouble: 2-6 */ - if (panelData[panelByte] >= 0 && panelData[panelByte] <= 0x04) { + if (panelData[panelByte] <= 0x04) { stream->print(F("Zone expander trouble: ")); printNumberOffset(panelByte, 2); return; @@ -920,7 +920,7 @@ void dscKeybusInterface::printPanelStatus5(byte panelByte) { * 0x00 - 0x04: Access codes 35-39 * 0x05 - 0x39: Access codes 43-95 */ - if (panelData[panelByte] >= 0x00 && panelData[panelByte] <= 0x39) { + if (panelData[panelByte] <= 0x39) { byte dscCode = panelData[panelByte] + 0x23; stream->print(F("Armed: ")); printPanelAccessCode(dscCode, false); @@ -991,7 +991,7 @@ void dscKeybusInterface::printPanelStatus17(byte panelByte) { * 0x00 - 0x24: *2: Access code 1-32, 40-42 * 0x84 - 0xBD: *2: Access codes 35-39, 43-95 */ - if (panelData[panelByte] >= 0 && panelData[panelByte] <= 0x24) { + if (panelData[panelByte] <= 0x24) { byte dscCode = panelData[panelByte] + 1; stream->print(F("*2: ")); printPanelAccessCode(dscCode); @@ -1042,10 +1042,10 @@ void dscKeybusInterface::printPanelStatus18(byte panelByte) { /* * *7/User/Auto-arm cancel by access codes 35-95 * - * 0x00 - 0x04: *7/*Access codes 35-39 - * 0x05 - 0x39: *7/*Access codes 43-95 + * 0x00 - 0x04: *7, * Access codes 35-39 + * 0x05 - 0x39: *7, * Access codes 43-95 */ - if (panelData[panelByte] >= 0x00 && panelData[panelByte] <= 0x39) { + if (panelData[panelByte] <= 0x39) { byte dscCode = panelData[panelByte] + 0x23; printPanelAccessCode(dscCode, false); return; @@ -1165,7 +1165,7 @@ void dscKeybusInterface::printPanel_0x05() { * Byte 0 1 2 3 4 5 6 7 8 9 */ void dscKeybusInterface::printPanel_0x0A_0F() { - byte partition; + byte partition = 0; switch (panelData[0]) { case 0x0A: partition = 1; break; case 0x0F: partition = 2; break; @@ -1338,7 +1338,7 @@ void dscKeybusInterface::printPanel_0x1C() { * Byte 0 1 2 3 4 5 6 */ void dscKeybusInterface::printPanel_0x22_28_33_39() { - byte expander; + byte expander = 0; switch (panelData[0]) { case 0x22: expander = 0; break; case 0x28: expander = 1; break; @@ -1575,7 +1575,7 @@ void dscKeybusInterface::printPanel_0x58() { * Byte 0 1 2 3 4 5 6 7 */ void dscKeybusInterface::printPanel_0x5D_63() { - byte partition; + byte partition = 0; switch (panelData[0]) { case 0x5D: partition = 1; break; case 0x63: partition = 2; break; @@ -2257,7 +2257,7 @@ void dscKeybusInterface::printPanel_0xE6() { * Byte 0 1 2 3 4 5 6 7 8 9 10 */ void dscKeybusInterface::printPanel_0xE6_0x01_06_20_21() { - byte partition; + byte partition = 0; switch(panelData[2]) { case 0x01: partition = 3; break; case 0x02: partition = 4; break; @@ -2309,7 +2309,7 @@ void dscKeybusInterface::printPanel_0xE6_0x01_06_20_21() { * Byte 0 1 2 3 4 5 6 7 8 */ void dscKeybusInterface::printPanel_0xE6_0x08_0A_0C_0E() { - byte expander; + byte expander = 0; switch (panelData[2]) { case 0x08: expander = 4; break; case 0x0A: expander = 5; break; diff --git a/src/dscKeybusProcessData.cpp b/src/dscKeybusProcessData.cpp index 8c7f03b..7289533 100644 --- a/src/dscKeybusProcessData.cpp +++ b/src/dscKeybusProcessData.cpp @@ -46,7 +46,7 @@ void dscKeybusInterface::resetStatus() { // Sets the panel time -bool dscKeybusInterface::setTime(unsigned int year, byte month, byte day, byte hour, byte minute, const char* accessCode) { +bool dscKeybusInterface::setTime(unsigned int year, byte month, byte day, byte hour, byte minute, const char* accessCode, byte timePartition) { // Loops if a previous write is in progress while(writeKeyPending || writeKeysPending) { @@ -88,7 +88,20 @@ bool dscKeybusInterface::setTime(unsigned int year, byte month, byte day, byte h strcat(timeEntry, timeChar); strcat(timeEntry, "#"); - write(timeEntry); + + if (writePartition != timePartition) { + byte previousPartition = writePartition; + writePartition = timePartition; + write(timeEntry); + while(writeKeyPending || writeKeysPending) { + loop(); + #if defined(ESP8266) + yield(); + #endif + } + writePartition = previousPartition; + } + else write(timeEntry); return true; } @@ -793,7 +806,7 @@ void dscKeybusInterface::processPanelStatus5(byte partition, byte panelByte) { * 0x00 - 0x04: Access codes 35-39 * 0x05 - 0x39: Access codes 43-95 */ - if (panelData[panelByte] >= 0x00 && panelData[panelByte] <= 0x39) { + if (panelData[panelByte] <= 0x39) { byte dscCode = panelData[panelByte] + 0x23; processPanelAccessCode(partitionIndex, dscCode, false); return;