Advertisement
penright

Untitled

Jan 14th, 2022
164
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.72 KB | None | 0 0
  1. #include "pvvx_mithermometer.h"
  2. #include "esphome/core/log.h"
  3.  
  4. #ifdef USE_ESP32
  5.  
  6. namespace esphome {
  7. namespace pvvx_mithermometer {
  8.  
  9. static const char *const TAG = "pvvx_mithermometer";
  10.  
  11. void PVVXMiThermometer::dump_config() {
  12.   ESP_LOGCONFIG(TAG, "PVVX MiThermometer");
  13.   LOG_SENSOR("  ", "Temperature", this->temperature_);
  14.   LOG_SENSOR("  ", "Humidity", this->humidity_);
  15.   LOG_SENSOR("  ", "Battery Level", this->battery_level_);
  16.   LOG_SENSOR("  ", "Battery Voltage", this->battery_voltage_);
  17.   LOG_SENSOR("  ", "Flag Value", this->flag_value_);
  18.   LOG_BINARY_SENSOR("  ", "Reed Switch", this->reed_switch_);
  19. }
  20.  
  21. bool PVVXMiThermometer::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
  22.   if (device.address_uint64() != this->address_) {
  23.     ESP_LOGVV(TAG, "parse_device(): unknown MAC address.");
  24.     return false;
  25.   }
  26.   ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str());
  27.  
  28.   bool success = false;
  29.   for (auto &service_data : device.get_service_datas()) {
  30.     auto res = parse_header_(service_data);
  31.     if (!res.has_value()) {
  32.       continue;
  33.     }
  34.     if (!(parse_message_(service_data.data, *res))) {
  35.       continue;
  36.     }
  37.     if (!(report_results_(res, device.address_str()))) {
  38.       continue;
  39.     }
  40.     if (res->temperature.has_value() && this->temperature_ != nullptr)
  41.       this->temperature_->publish_state(*res->temperature);
  42.     if (res->humidity.has_value() && this->humidity_ != nullptr)
  43.       this->humidity_->publish_state(*res->humidity);
  44.     if (res->battery_level.has_value() && this->battery_level_ != nullptr)
  45.       this->battery_level_->publish_state(*res->battery_level);
  46.     if (res->battery_voltage.has_value() && this->battery_voltage_ != nullptr)
  47.       this->battery_voltage_->publish_state(*res->battery_voltage);
  48.     if (res->flag_value.has_value() && this->flag_value_ != nullptr)
  49.       this->flag_value_->publish_state(*res->flag_value);
  50.     if (res->reed_switch.has_value() && this->reed_switch_ != nullptr)
  51.       this->reed_switch_->publish_state(*res->reed_switch);
  52.     success = true;
  53.   }
  54.  
  55.   return success;
  56. }
  57.  
  58. optional<ParseResult> PVVXMiThermometer::parse_header_(const esp32_ble_tracker::ServiceData &service_data) {
  59.   ParseResult result;
  60.   if (!service_data.uuid.contains(0x1A, 0x18)) {
  61.     ESP_LOGVV(TAG, "parse_header(): no service data UUID magic bytes.");
  62.     return {};
  63.   }
  64.  
  65.   auto raw = service_data.data;
  66.  
  67.   static uint8_t last_frame_count = 0;
  68.   if (last_frame_count == raw[13]) {
  69.     ESP_LOGVV(TAG, "parse_header(): duplicate data packet received (%hhu).", last_frame_count);
  70.     return {};
  71.   }
  72.   last_frame_count = raw[13];
  73.  
  74.   return result;
  75. }
  76.  
  77. bool PVVXMiThermometer::parse_message_(const std::vector<uint8_t> &message, ParseResult &result) {
  78.   /*
  79.   All data little endian
  80.   uint8_t     size;   // = 19
  81.   uint8_t     uid;    // = 0x16, 16-bit UUID
  82.   uint16_t    UUID;   // = 0x181A, GATT Service 0x181A Environmental Sensing
  83.   uint8_t     MAC[6]; // [0] - lo, .. [5] - hi digits
  84.   int16_t     temperature;    // x 0.01 degree     [6,7]
  85.   uint16_t    humidity;       // x 0.01 %          [8,9]
  86.   uint16_t    battery_mv;     // mV                [10,11]
  87.   uint8_t     battery_level;  // 0..100 %          [12]
  88.   uint8_t     counter;        // measurement count [13]
  89.   int         flags;          // details below     [14]                    
  90.                               // flags bit0: Reed Switch, input
  91.                               // flags bit1: GPIO_TRG pin output value (pull Up/Down)
  92.                               // flags bit2: Output GPIO_TRG pin is controlled according to the set parameters
  93.                               // flags bit3: Temperature trigger event
  94.                               // flags bit4: Humidity trigger event
  95.   */
  96.  
  97.   const uint8_t *data = message.data();
  98.   const int data_length = 15;
  99.  
  100.   if (message.size() != data_length) {
  101.     ESP_LOGVV(TAG, "parse_message(): payload has wrong size (%d)!", message.size());
  102.     return false;
  103.   }
  104.  
  105.   // int16_t     temperature;    // x 0.01 degree     [6,7]
  106.   const int16_t temperature = int16_t(data[6]) | (int16_t(data[7]) << 8);
  107.   result.temperature = temperature / 1.0e2f;
  108.  
  109.   // uint16_t    humidity;       // x 0.01 %          [8,9]
  110.   const int16_t humidity = uint16_t(data[8]) | (uint16_t(data[9]) << 8);
  111.   result.humidity = humidity / 1.0e2f;
  112.  
  113.   // uint16_t    battery_mv;     // mV                [10,11]
  114.   const int16_t battery_voltage = uint16_t(data[10]) | (uint16_t(data[11]) << 8);
  115.   result.battery_voltage = battery_voltage / 1.0e3f;
  116.  
  117.   // uint8_t     battery_level;  // 0..100 %          [12]
  118.   result.battery_level = uint8_t(data[12]);
  119.  
  120.   // int         flag_value      //                   [14]
  121.   result.flag_value = int(data[14]);
  122.  
  123.   // Checking bit 0 on flag byte [14]
  124.   result.reed_switch = int(data[14]) & 1;
  125.   return true;
  126. }
  127.  
  128. bool PVVXMiThermometer::report_results_(const optional<ParseResult> &result, const std::string &address) {
  129.   if (!result.has_value()) {
  130.     ESP_LOGVV(TAG, "report_results(): no results available.");
  131.     return false;
  132.   }
  133.  
  134.   ESP_LOGD(TAG, "Got PVVX MiThermometer (%s):", address.c_str());
  135.  
  136.   if (result->temperature.has_value()) {
  137.     ESP_LOGD(TAG, "  Temperature: %.2f °C", *result->temperature);
  138.   }
  139.   if (result->humidity.has_value()) {
  140.     ESP_LOGD(TAG, "  Humidity: %.2f %%", *result->humidity);
  141.   }
  142.   if (result->battery_level.has_value()) {
  143.     ESP_LOGD(TAG, "  Battery Level: %.0f %%", *result->battery_level);
  144.   }
  145.   if (result->battery_voltage.has_value()) {
  146.     ESP_LOGD(TAG, "  Battery Voltage: %.3f V", *result->battery_voltage);
  147.   }
  148.   if (result->flag_value.has_value()) {
  149.     ESP_LOGD(TAG, "  Flag Value: %u", *result->flag_value);
  150.   }
  151.   if (result->reed_switch.has_value()) {
  152.     ESP_LOGD(TAG, "  Reed Switch: %s", ONOFF(*result->reed_switch));
  153.   }
  154.  
  155.   return true;
  156. }
  157.  
  158. }  // namespace pvvx_mithermometer
  159. }  // namespace esphome
  160.  
  161. #endif
  162.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement