include "esphome.h" //#define DEBUG //#define MSB #ifdef DEBUG #define debug_print(x, ...) Serial.print(x, ##__VA_ARGS__) #define debug_println(x, ...) Serial.println(x, ##__VA_ARGS__) #else #define debug_print(x, ...) #define debug_println(x, ...) #endif #define RX_PIN 3 #define IS_START_PULSE(interval) (interval >= 7500 && interval <= 10500) #define IS_MARK_PULSE(interval) (interval >= 250 && interval <= 750) #define IS_LOW_PULSE(interval) (interval >= 1200 && interval <= 2800) #define IS_HIGH_PULSE(interval) (interval >= 3200 && interval <= 4800) #define IS_GLITCH(interval) (interval < 250) enum sampling_state {WAIT_FOR_START, DATA_MARK, DATA_BIT, DATA_RECEIVED }; static const char* TAG = "RF433_Rain_Sensor"; bool have_data = false; bool have_batt_data = false; bool have_id_data = false; bool lowbat = false; int Temp = 0; int Rain = 0; int Id = 0; // --------------------------------------------------------------------------- class RF433_Rain_Sensor : public PollingComponent { public: Sensor *temp_sensor = new Sensor(); Sensor *rain_sensor = new Sensor(); RF433_Rain_Sensor() : PollingComponent(500) { } float get_setup_priority() const override { return esphome::setup_priority::HARDWARE; } static void ICACHE_RAM_ATTR pin_ISR() { static unsigned long last = 0; static unsigned long micros_now; static byte nibble[9] = {0,0,0,0,0,0,0,0,0}; static uint16_t pulse; static byte sampling_state = WAIT_FOR_START; static byte bits = 0; static byte npos = 0; static byte chksum = 0; micros_now = micros(); pulse = micros_now - last; // ignore glitches if (IS_GLITCH(pulse)) pulse = 0; else last = micros_now; // state machine for decoding on the fly switch (sampling_state) { case WAIT_FOR_START: if (IS_START_PULSE(pulse)) { sampling_state = DATA_MARK; bits = 0; } break; case DATA_MARK: if (IS_MARK_PULSE(pulse)) { sampling_state = DATA_BIT; } else { sampling_state = WAIT_FOR_START; } break; case DATA_BIT: // LSB if (IS_LOW_PULSE(pulse)) { #ifdef MSB nibble[bits/4] &= ~(1<<(3-(bits%4))); #else nibble[bits/4] &= ~(1<<(bits%4)); #endif bits++; sampling_state = DATA_MARK; } else if (IS_HIGH_PULSE(pulse)) { #ifdef MSB nibble[bits/4] |= 1<<(3-(bits%4)); #else nibble[bits/4] |= 1<<(bits%4); #endif bits++; sampling_state = DATA_MARK; } else { sampling_state = WAIT_FOR_START; } if (bits == 36) sampling_state = DATA_RECEIVED; break; case DATA_RECEIVED: chksum = 0; for (npos=0;npos<8;npos++) { chksum += nibble[npos]; } chksum &= 0x0F; ESP_LOGD(TAG, "Frame Received: 0x%X%X%X%X%X%X%X%X%X", nibble[0],nibble[1],nibble[2],nibble[3],nibble[4],nibble[5],nibble[6],nibble[7],nibble[8]); if (chksum == nibble[8]) { Temp = (nibble[5]<<8) + (nibble[4]<<4) + nibble[3]; Rain = (((nibble[2] & 0xC0)>>2)<<8) + (nibble[7]<<4) + nibble[6]; have_data = true; if ((nibble[2] & 0x8) > 0) { lowbat = true; } else { lowbat = false; } have_batt_data = true; Id = (nibble[1]<<4) + nibble[0]; have_id_data = true; } bits = 0; sampling_state = WAIT_FOR_START; break; } } // ------------------------------------------------------------------------- void setup() override { // Prepare RF input pin Serial.end(); // we are using rx pin for reciever (3) pinMode(RX_PIN, INPUT); attachInterrupt(RX_PIN, pin_ISR, CHANGE); } // ------------------------------------------------------------------------- void update() override { // This is the actual sensor reading logic. if (have_data) { temp_sensor->publish_state(Temp/10.0); rain_sensor->publish_state(Rain*0.5); have_data = false; } } }; // --------------------------------------------------------------------------- class Batt_RF433_Rain_Sensor : public PollingComponent, public BinarySensor { public: // constructor Batt_RF433_Rain_Sensor() : PollingComponent(10000) {} void setup() override { // This will be called by App.setup() } void update() override { if (have_batt_data) { if (lowbat) { publish_state(true); } else { publish_state(false); } have_batt_data = false; } } }; // --------------------------------------------------------------------------- class ID_RF433_Rain_Sensor : public PollingComponent, public Sensor { public: // constructor ID_RF433_Rain_Sensor() : PollingComponent(10000) {} void setup() override { // This will be called by App.setup() } void update() override { if (have_id_data) { publish_state(Id); have_id_data = false; } } };