From df13de502de40787810e036f531c1a1acb4d1dfe Mon Sep 17 00:00:00 2001 From: Matt Way Date: Sat, 2 Dec 2023 11:38:31 +1100 Subject: [PATCH] Create Hotdog script to interface between MQTT and the radio --- .gitignore | 1 + HDPacketBuilder.h | 185 ++++++++++++++++++++++++++++++++++++++++++++++ Hotdog.ino | 119 +++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+) create mode 100644 .gitignore create mode 100644 HDPacketBuilder.h create mode 100644 Hotdog.ino diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..37693d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +arduino_secrets.h \ No newline at end of file diff --git a/HDPacketBuilder.h b/HDPacketBuilder.h new file mode 100644 index 0000000..f66ced4 --- /dev/null +++ b/HDPacketBuilder.h @@ -0,0 +1,185 @@ +#include + +#define LENGTH_17 (0x11) +#define LENGTH_21 (0x15) +#define LENGTH_25 (0x19) + +#define VERSION_5 (0x05) +#define VERSION_6 (0x06) + +uint8_t rollingCode1 = 0xAC; +uint8_t rollingCode2 = 0x82; + +uint8_t buf[32]; + +CRC16 crc(0x755B, 0x0, 0xBA68, false, false); + +void setPacketLength(uint8_t); +void setConstants(); +void setSourceRemoteAddress(); +void setHubSourceAddress(); +void setRollingCodes(); +void setProtocolVersion(uint8_t); +void calculateCRC(); + + +void constructUpPacket() +{ + setPacketLength(LENGTH_17); + setConstants(); + setSourceRemoteAddress(); + setRollingCodes(); + setProtocolVersion(VERSION_6); + + buf[11] = 0x04; // Shade ID (group 4 for now) + buf[12] = 0x00; // Shade ID + + buf[16] = 0x55; // Command + buf[17] = 0x00; // Empty? + + calculateCRC(); +} + +void constructDownPacket() +{ + setPacketLength(LENGTH_17); + setConstants(); + setSourceRemoteAddress(); + setRollingCodes(); + setProtocolVersion(VERSION_6); + + buf[11] = 0x04; // Shade ID (group 4 for now) + buf[12] = 0x00; // Shade ID + + buf[16] = 0x44; // Command + buf[17] = 0x00; // Empty? + + calculateCRC(); +} + +void constructStopPacket() +{ + setPacketLength(LENGTH_17); + setConstants(); + setSourceRemoteAddress(); + setRollingCodes(); + setProtocolVersion(VERSION_6); + + buf[11] = 0x04; // Shade ID (group 4 for now) + buf[12] = 0x00; // Shade ID + + buf[16] = 0x53; // Command + buf[17] = 0x00; // Empty? + + calculateCRC(); +} + +void constructPositionPacket(float percentage) +{ + setPacketLength(LENGTH_21); + setConstants(); + setHubSourceAddress(); // TODO: Will this source address work? + setRollingCodes(); + setProtocolVersion(VERSION_5); + + buf[11] = 0x4E; // Shade ID? + buf[12] = 0xF1; // Shade ID? + + buf[15] = 0x3F; // Command + buf[16] = 0x5A; // Empty? + + buf[17] = 0x04; // Constant in this size packet? + buf[18] = 0x40; // Constant in this size packet? + buf[19] = 0x50; // Constant in this size packet? + + uint16_t position = (uint16_t)(0xFFFF * percentage); + + buf[20] = (uint8_t)(position & 0x00FF); + buf[21] = (uint8_t)((position & 0xFF00) >> 8); + + calculateCRC(); +} + +void setPacketLength(uint8_t length) { + buf[0] = length; // Packet size +} + +void setConstants() { + buf[1] = 0x00; // Constant? + buf[2] = 0x05; // Constant? + + buf[4] = 0xff; // Constant? + buf[5] = 0xff; // Constant? + + buf[8] = 0x86; // Constant? + + buf[15] = 0x52; // Constant? +} + +void setSourceRemoteAddress() { + buf[6] = 0x36; // Source address? + buf[7] = 0x9e; // Source address? + + buf[13] = 0x36; // Source address again? + buf[14] = 0x9e; // Source address again? +} + +void setHubSourceAddress() { + buf[6] = 0x00; // Source address? + buf[7] = 0x00; // Source address? + + buf[13] = 0x00; // Source address again? + buf[14] = 0x00; // Source address again? +} + +void setRollingCodes() { + buf[3] = rollingCode1; // Rolling code 1 + buf[10] = rollingCode2; // Rolling code 2 +} + +void setProtocolVersion(uint8_t version) { + buf[9] = version; // Protocol version? +} + +void calculateCRC() { // must be called after the buffer has been filled + crc.restart(); + uint8_t length = buf[0]; + switch(length) { + case 0x11: + crc.setXorOut(0xBA68); + break; + case 0x15: + crc.setXorOut(0xE10C); + break; + case 0x19: + crc.setXorOut(0x89A0); + break; + default: + Serial.print("Unsupported length ("); + Serial.print(length); + Serial.println("). Cannot calculate CRC"); + return; + } + crc.add(buf, length + 1); + uint16_t result = crc.calc(); + uint8_t checksum1 = (uint8_t)((result & 0xFF00) >> 8); + uint8_t checksum2 = (uint8_t)(result & 0x00FF); + + buf[length + 1] = checksum1; // Checksum + buf[length + 2] = checksum2; // Checksum +} + +void printHex(uint8_t num) { //print a byte as two hex chars + char hexCar[3]; + sprintf(hexCar, "%02X", num); + Serial.print(hexCar); +} + +void printBuffer() //print a byte array as hex chars +{ + uint8_t bytecount = buf[0] + 3; + for (int i = 0; i < bytecount; i++) { + printHex(buf[i]); + } + Serial.println(); +} \ No newline at end of file diff --git a/Hotdog.ino b/Hotdog.ino new file mode 100644 index 0000000..ebf8cd1 --- /dev/null +++ b/Hotdog.ino @@ -0,0 +1,119 @@ +#include "arduino_secrets.h" +#include "HDPacketBuilder.h" +#include +#include // library by TMRh20 + +#define SER_BAUDRATE (115200) + +// pins for: esp8266 NodeMCU v3 dev board +#define RF_CE_PIN (5) // pins for: esp +#define RF_CS_PIN (15) // pins for: esp +#define RF_IRQ_PIN (4) // run a jumper from IRQ pin to pin 2 + +EspMQTTClient client( + SECRET_WIFI_SSID, // Wifi SSID + SECRET_WIFI_PASSWORD, // Wifi Password + SECRET_MQTT_SERVER_IP, // MQTT Broker server IP + SECRET_MQTT_USERNAME, // MQTT Username + SECRET_MQTT_PASSWORD, // MQTT Password + "hotdog", // MQTT Client ID + 1883 +); + +byte addr[3] = { 0xC0, 0xC8, 0x2E }; // The address was captured as "2EC8C0" and the bytes were reversed + +RF24 radio(RF_CE_PIN, RF_CS_PIN); + +void setup() { + for (int i = 0; i < 32; i++) { + buf[i] = 0x00; + } + + Serial.begin(SER_BAUDRATE); + + client.setKeepAlive(10); + client.enableLastWillMessage("hotdog/availability", "offline", true); + client.enableDebuggingMessages(); + + radio.begin(); + radioTransmitSetup(); + + for (int i = 0; i < 32; i++) { + buf[i] = 0x00; + } + + Serial.println("Ready"); +} + +void onConnectionEstablished() { + + client.subscribe("hotdog/test_mqtt_blind/set", [] (const String &payload) { + Serial.print("Set on test_mqtt_blind: "); + Serial.println(payload); + if (payload == "OPEN") { + constructUpPacket(); + printBuffer(); + sendCommand(buf); + } else if (payload == "CLOSE") { + constructDownPacket(); + printBuffer(); + sendCommand(buf); + } else if (payload == "STOP") { + constructStopPacket(); + printBuffer(); + sendCommand(buf); + } + }); + + client.subscribe("hotdog/test_mqtt_blind/set_position", [] (const String &payload) { + Serial.print("Set position on test_mqtt_blind: "); + Serial.println(payload); + }); + + client.publish("hotdog/availability", "online", true); +} + +void loop() { + client.loop(); +} + +void radioTransmitSetup() { + radio.stopListening(); + radio.powerDown(); + radio.begin(); + delay(100); + Serial.println(); + radio.setChannel(0x07); //shooting for 2.407 GHz + radio.setDataRate(RF24_1MBPS); //can go at 250kbs, 1Mbs, 2Mbs + radio.setPALevel(RF24_PA_HIGH); //transmit power + radio.disableCRC(); + radio.setAutoAck(false); + radio.setAddressWidth(3); + radio.setRetries(0, 0); + + radio.openWritingPipe(addr); + radio.powerUp(); + //radio.printDetails(); + //radio.printPrettyDetails(); + Serial.println("Ready to Transmit"); +} + +void sendCommand(byte * byteArray) //transmit a command +{ + uint8_t bytecount = byteArray[0] + 3; + for (int j = 1; j < 5; j++) { + radio.setAddressWidth(3); + radio.disableCRC(); + radio.setAutoAck(false); + radio.openWritingPipe(addr); + for (int i = 1; i < 200; i++) { + radio.writeFast(byteArray, bytecount); + } + delay(500); + radio.flush_tx(); + radio.txStandBy(); + } + + rollingCode1++; + rollingCode2++; +} \ No newline at end of file