mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-28 05:06:32 +00:00
Add GM861 optional heartbeat
This commit is contained in:
parent
eccc1af0a2
commit
91523fd90b
@ -834,6 +834,7 @@
|
|||||||
//#define USE_LOX_O2 // Add support for LuminOx LOX O2 Sensor (+0k8 code)
|
//#define USE_LOX_O2 // Add support for LuminOx LOX O2 Sensor (+0k8 code)
|
||||||
//#define USE_GM861 // Add support for GM861 1D and 2D Bar Code Reader (+1k3 code)
|
//#define USE_GM861 // Add support for GM861 1D and 2D Bar Code Reader (+1k3 code)
|
||||||
// #define GM861_DECODE_AIM // Decode AIM-id (+0k3 code)
|
// #define GM861_DECODE_AIM // Decode AIM-id (+0k3 code)
|
||||||
|
// #define GM861_HEARTBEAT // Enable heartbeat (+0k2 code)
|
||||||
|
|
||||||
// -- Power monitoring sensors --------------------
|
// -- Power monitoring sensors --------------------
|
||||||
#define USE_ENERGY_SENSOR // Add support for Energy Monitors (+14k code)
|
#define USE_ENERGY_SENSOR // Add support for Energy Monitors (+14k code)
|
||||||
|
@ -37,6 +37,10 @@
|
|||||||
#define XSNS_107 107
|
#define XSNS_107 107
|
||||||
|
|
||||||
//#define GM861_DECODE_AIM // Decode AIM-id (+0k3 code)
|
//#define GM861_DECODE_AIM // Decode AIM-id (+0k3 code)
|
||||||
|
//#define GM861_HEARTBEAT // Enable heartbeat
|
||||||
|
|
||||||
|
#define GM861_BAUDRATE 9600 // Serial baudrate
|
||||||
|
#define GM861_GUI_LENGTH 30 // Max number of code characters in GUI
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#define GPIO_GM861_TX 304
|
#define GPIO_GM861_TX 304
|
||||||
@ -87,13 +91,14 @@ enum Gm861States {
|
|||||||
#include <TasmotaSerial.h>
|
#include <TasmotaSerial.h>
|
||||||
TasmotaSerial *Gm861Serial = nullptr;
|
TasmotaSerial *Gm861Serial = nullptr;
|
||||||
|
|
||||||
struct GDK {
|
typedef struct {
|
||||||
char barcode[30];
|
char barcode[GM861_GUI_LENGTH];
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
bool heartbeat;
|
uint8_t heartbeat;
|
||||||
bool read;
|
bool read;
|
||||||
} Gm861;
|
} tGm861;
|
||||||
|
tGm861 *Gm861 = nullptr;
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
@ -159,15 +164,15 @@ void Gm861Send(uint32_t type, uint32_t len, uint32_t address, uint32_t data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Gm861SetZone(uint32_t address, uint32_t data) {
|
void Gm861SetZone(uint32_t address, uint32_t data) {
|
||||||
Gm861.read = false;
|
Gm861->read = false;
|
||||||
uint32_t len = 1;
|
uint32_t len = 1;
|
||||||
if (0x2A == address) { len = 2; } // Baudrate
|
if (0x2A == address) { len = 2; } // Baudrate
|
||||||
Gm861Send(8, len, address, data);
|
Gm861Send(8, len, address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gm861GetZone(uint32_t address) {
|
void Gm861GetZone(uint32_t address) {
|
||||||
Gm861.read = true;
|
Gm861->read = true;
|
||||||
Gm861.index = address;
|
Gm861->index = address;
|
||||||
uint32_t data = 1;
|
uint32_t data = 1;
|
||||||
if (0x2A == address) { data = 2; } // Baudrate
|
if (0x2A == address) { data = 2; } // Baudrate
|
||||||
Gm861Send(7, 1, address, data);
|
Gm861Send(7, 1, address, data);
|
||||||
@ -196,20 +201,24 @@ void Gm861SerialInput(void) {
|
|||||||
// 02 00 00 01 00 33 31 - Command acknowledge
|
// 02 00 00 01 00 33 31 - Command acknowledge
|
||||||
// 02 00 00 01 01 23 10 - Command result (Zonebyte 96 - 0x60)
|
// 02 00 00 01 01 23 10 - Command result (Zonebyte 96 - 0x60)
|
||||||
// 02 00 00 02 39 01 C1 4C - Command result (Zonebytes 42/43 - 0x2A)
|
// 02 00 00 02 39 01 C1 4C - Command result (Zonebytes 42/43 - 0x2A)
|
||||||
if (Gm861.read) {
|
if (Gm861->read) {
|
||||||
uint32_t result = buffer[4];
|
uint32_t result = buffer[4];
|
||||||
if (2 == buffer[3]) { // Length
|
if (2 == buffer[3]) { // Length
|
||||||
result += (buffer[5] << 8);
|
result += (buffer[5] << 8);
|
||||||
}
|
}
|
||||||
Gm861.read = false;
|
Gm861->read = false;
|
||||||
Response_P(S_JSON_COMMAND_INDEX_NVALUE, PSTR("GM861Zone"), Gm861.index, result);
|
Response_P(S_JSON_COMMAND_INDEX_NVALUE, PSTR("GM861Zone"), Gm861->index, result);
|
||||||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR("GM861Zone"));
|
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR("GM861Zone"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (3 == buffer[0]) { // Heartbeat
|
else if (3 == buffer[0]) { // Heartbeat
|
||||||
// 03 00 00 01 00 33 31 - Heartbeat response
|
// 03 00 00 01 00 33 31 - Heartbeat response
|
||||||
// 03 00 0A 30 33 32 31 35 36 33 38 34 30 - Scan response with zone byte 96 = 0x81
|
// 03 00 0A 30 33 32 31 35 36 33 38 34 30 - Scan response with zone byte 96 = 0x81
|
||||||
Gm861.heartbeat = true;
|
#ifdef GM861_HEARTBEAT
|
||||||
|
if ((0 == buffer[2]) && (1 == buffer[3]) && (0 == buffer[4])) {
|
||||||
|
Gm861->heartbeat = 0;
|
||||||
|
}
|
||||||
|
#endif // GM861_HEARTBEAT
|
||||||
}
|
}
|
||||||
} else { // Bar code
|
} else { // Bar code
|
||||||
// 38 37 31 31 32 31 38 39 37 32 38 37 35 0D - Barcode 8711218972875
|
// 38 37 31 31 32 31 38 39 37 32 38 37 35 0D - Barcode 8711218972875
|
||||||
@ -224,9 +233,9 @@ void Gm861SerialInput(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prepare GUI result
|
// Prepare GUI result
|
||||||
snprintf_P(Gm861.barcode, sizeof(Gm861.barcode) -3, PSTR("%s"), buffer + offset);
|
snprintf_P(Gm861->barcode, sizeof(Gm861->barcode) -3, PSTR("%s"), buffer + offset);
|
||||||
if (strlen(buffer) > sizeof(Gm861.barcode) -3) {
|
if (strlen(buffer) > sizeof(Gm861->barcode) -3) {
|
||||||
strcat(Gm861.barcode, "...");
|
strcat(Gm861->barcode, "...");
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponseTime_P(PSTR(",\"GM861\":{"));
|
ResponseTime_P(PSTR(",\"GM861\":{"));
|
||||||
@ -246,14 +255,16 @@ void Gm861SerialInput(void) {
|
|||||||
|
|
||||||
void Gm861Init(void) {
|
void Gm861Init(void) {
|
||||||
if (PinUsed(GPIO_GM861_RX) && PinUsed(GPIO_GM861_TX)) {
|
if (PinUsed(GPIO_GM861_RX) && PinUsed(GPIO_GM861_TX)) {
|
||||||
|
Gm861 = (tGm861*)calloc(sizeof(tGm861), 1);
|
||||||
|
if (!Gm861) { return; }
|
||||||
|
|
||||||
Gm861Serial = new TasmotaSerial(Pin(GPIO_GM861_RX), Pin(GPIO_GM861_TX), 1);
|
Gm861Serial = new TasmotaSerial(Pin(GPIO_GM861_RX), Pin(GPIO_GM861_TX), 1);
|
||||||
if (Gm861Serial->begin(9600)) {
|
if (Gm861Serial->begin(GM861_BAUDRATE)) {
|
||||||
if (Gm861Serial->hardwareSerial()) {
|
if (Gm861Serial->hardwareSerial()) {
|
||||||
ClaimSerial();
|
ClaimSerial();
|
||||||
}
|
}
|
||||||
Gm861.barcode[0] = '0'; // No barcode yet
|
Gm861->barcode[0] = '0'; // No barcode yet
|
||||||
Gm861.state = GM861_STATE_INIT_OFFSET;
|
Gm861->state = GM861_STATE_INIT_OFFSET;
|
||||||
// AddLog(LOG_LEVEL_INFO, PSTR("GM8: Connected"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,12 +280,12 @@ void Gm861StateMachine(void) {
|
|||||||
Serial output:
|
Serial output:
|
||||||
14:39:04.887-027 DMP: 02 00 00 62 D6 00 20 01 00 0A 32 01 2C 00 87 3C 01 A0 1C 32 03 00 80 00 06 00 00 00 00 00 00 00 00 00 00 00 00 02 80 3C 00 00 00 06 00 00 39 01 05 64 0D 0D 0D 01 0D 01 04 80 09 04 80 05 04 80 01 04 80 01 08 04 80 08 04 80 08 04 80 08 04 80 08 01 80 00 00 00 04 80 01 01 00 00 00 00 04 80 00 00 03 00 01 00 2D 9E
|
14:39:04.887-027 DMP: 02 00 00 62 D6 00 20 01 00 0A 32 01 2C 00 87 3C 01 A0 1C 32 03 00 80 00 06 00 00 00 00 00 00 00 00 00 00 00 00 02 80 3C 00 00 00 06 00 00 39 01 05 64 0D 0D 0D 01 0D 01 04 80 09 04 80 05 04 80 01 04 80 01 08 04 80 08 04 80 08 04 80 08 04 80 08 01 80 00 00 00 04 80 01 01 00 00 00 00 04 80 00 00 03 00 01 00 2D 9E
|
||||||
*/
|
*/
|
||||||
if (!Gm861.state) { return; }
|
if (!Gm861->state) { return; }
|
||||||
|
|
||||||
switch (Gm861.state) {
|
switch (Gm861->state) {
|
||||||
case GM861_STATE_RESET:
|
case GM861_STATE_RESET:
|
||||||
Gm861SetZone(0xD9, 0x50); // Factory reset
|
Gm861SetZone(0xD9, 0x50); // Factory reset
|
||||||
Gm861.state = GM861_STATE_SETUP_CODE_ON +7; // Add time for reset to complete
|
Gm861->state = GM861_STATE_SETUP_CODE_ON +7; // Add time for reset to complete
|
||||||
break;
|
break;
|
||||||
case GM861_STATE_SETUP_CODE_ON:
|
case GM861_STATE_SETUP_CODE_ON:
|
||||||
Gm861SetZone(0x00, 0xD6); // Set LED on, Mute off, Normal lighting, Normal brightness, Continuous mode (Default: setup code on)
|
Gm861SetZone(0x00, 0xD6); // Set LED on, Mute off, Normal lighting, Normal brightness, Continuous mode (Default: setup code on)
|
||||||
@ -290,9 +301,25 @@ void Gm861StateMachine(void) {
|
|||||||
AddLog(LOG_LEVEL_INFO, PSTR("GM8: Initialized"));
|
AddLog(LOG_LEVEL_INFO, PSTR("GM8: Initialized"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Gm861.state--;
|
Gm861->state--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef GM861_HEARTBEAT
|
||||||
|
void Gm861Heartbeat(void) {
|
||||||
|
if (!Gm861->state && (!(TasmotaGlobal.uptime % 10))) {
|
||||||
|
// It is recommended to send a heartbeat packet every 10 seconds
|
||||||
|
Gm861Send(10, 1, 0, 0); // Send heartbeat
|
||||||
|
Gm861->heartbeat++;
|
||||||
|
// If no correct reply is received for three consecutive times, the main control should be handle it accordingly.
|
||||||
|
if (Gm861->heartbeat > 3) {
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR("GM8: Heartbeat lost"));
|
||||||
|
Gm861->heartbeat = 0;
|
||||||
|
Gm861->state = GM861_STATE_RESET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // GM861_HEARTBEAT
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* Commands
|
* Commands
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
@ -326,7 +353,7 @@ void CmndGm816Save(void) {
|
|||||||
void CmndGm816Reset(void) {
|
void CmndGm816Reset(void) {
|
||||||
// GM861Reset 1 - Do factory reset and inititalize for serial comms
|
// GM861Reset 1 - Do factory reset and inititalize for serial comms
|
||||||
if (1 == XdrvMailbox.payload) {
|
if (1 == XdrvMailbox.payload) {
|
||||||
Gm861.state = GM861_STATE_RESET;
|
Gm861->state = GM861_STATE_RESET;
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -337,16 +364,6 @@ void CmndGm816Dump(void) {
|
|||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* Presentation
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER
|
|
||||||
void Gm861Show(void) {
|
|
||||||
WSContentSend_PD(PSTR("{s}GM816{m}%s{e}"), Gm861.barcode);
|
|
||||||
}
|
|
||||||
#endif // USE_WEBSERVER
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
Interface
|
Interface
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
@ -366,9 +383,14 @@ bool Xsns107(uint32_t function) {
|
|||||||
case FUNC_EVERY_250_MSECOND:
|
case FUNC_EVERY_250_MSECOND:
|
||||||
Gm861StateMachine();
|
Gm861StateMachine();
|
||||||
break;
|
break;
|
||||||
|
#ifdef GM861_HEARTBEAT
|
||||||
|
case FUNC_EVERY_SECOND:
|
||||||
|
Gm861Heartbeat();
|
||||||
|
break;
|
||||||
|
#endif // GM861_HEARTBEAT
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
case FUNC_WEB_SENSOR:
|
case FUNC_WEB_SENSOR:
|
||||||
Gm861Show();
|
WSContentSend_PD(PSTR("{s}GM816{m}%s{e}"), Gm861->barcode);
|
||||||
break;
|
break;
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
case FUNC_COMMAND:
|
case FUNC_COMMAND:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user