esp_zb_ieee_addr_t long_addr;
} zdo_info_user_ctx_t;
-static short temp_list[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+typedef struct aqi_data_s {
+ float pm10;
+ float pm25;
+} aqi_data_t;
+
+static int tempbuffer[TEMPBUFFERSIZE];
+static int tempbufferindex = 0;
+
+//= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static const char *TAG = "aqi";
static OW ow;
static bool zig_connected = false;
-static uint16_t cur_pm25 = 0;
+static aqi_data_t cur_pm = {
+ .pm10 = 0,
+ .pm25 = 0
+};
-static float pm25buffer[PM25BUFFERSIZE];
-static int pm25bufferindex = 0;
+static aqi_data_t pmbuffer[PMBUFFERSIZE];
+static int pmbufferindex = 0;
/********************* Define functions **************************/
static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask)
return err;
}
+void print_pmdata(aqi_data_t data){
+ ESP_LOGI(TAG, "pmdata pm10: %f, pm25: %f", data.pm10, data.pm25);
+}
// add new value to ringbuffer and return average of all, downcast to uint16_t
-uint16_t new_pm25_average(float new_val){
- pm25buffer[pm25bufferindex++] = new_val;
+aqi_data_t new_pm_average(aqi_data_t new_val){
+ pmbuffer[pmbufferindex++] = new_val;
+ aqi_data_t retval = {
+ .pm10 = 0,
+ .pm25 = 0,
+ };
// rollover
- if (pm25bufferindex == PM25BUFFERSIZE){
- pm25bufferindex = 0;
+ if (pmbufferindex == PMBUFFERSIZE){
+ pmbufferindex = 0;
}
- float total = 0;
+ float pm10_total = 0;
+ float pm25_total = 0;
int count = 0;
- for (int i = 0; i < PM25BUFFERSIZE; i++ ){
+ for (int i = 0; i < PMBUFFERSIZE; i++ ){
// ignore initial values
- if ( pm25buffer[i] != -1.0 ){
- total += pm25buffer[i];
+ if ( pmbuffer[i].pm10 != -1.0 ){
+ pm10_total += pmbuffer[i].pm10;
+ }
+ if ( pmbuffer[i].pm25 != -1.0 ){
+ pm25_total += pmbuffer[i].pm25;
+ // assuming both fields have the same "valid" count
+ count++;
+ }
+
+
+ }
+ // multiply * 100 for greater precision once sent
+ if (count != 0 ){
+ retval.pm10 = (pm10_total*100/count);
+ retval.pm25 = (pm25_total*100/count);
+ }
+
+ ESP_LOGI(TAG, "returning average pmdata to send: pm10 %f pm25 %f", retval.pm10, retval.pm25);
+ return retval;
+
+}
+
+int new_temp_average(short new_val){
+ tempbuffer[tempbufferindex++] = new_val;
+ // rollover
+ if (tempbufferindex == TEMPBUFFERSIZE){
+ tempbufferindex = 0;
+ }
+
+ int total = 0;
+ int count = 0;
+ for (int i = 0; i < TEMPBUFFERSIZE; i++ ){
+ // ignore invalid
+ if ( tempbuffer[i] != 0x8000 ){
+ total += tempbuffer[i];
count++;
}
}
- uint16_t retval = (uint16_t)(total*100/count);
- ESP_LOGI(TAG, "returning average pm25 to send: %d", retval);
+ int retval;
+ // we should only get here if all values are added are 0x8000 (aka no read)
+ // but it's still important to fill out just so we don't crash
+ // mainly, when ds18b20 is not connected or sensing properly
+ if (count == 0){
+ retval = 0x8000;
+ } else {
+ retval = (int)(total/count);
+ }
+ ESP_LOGI(TAG, "returning average temp to send: %d", retval);
return retval;
}
-void init_pm25buffer(){
- for (int i = 0; i < PM25BUFFERSIZE; i++){
- pm25buffer[i] = -1.0;
+
+void init_pmbuffer(){
+ for (int i = 0; i < PMBUFFERSIZE; i++){
+ pmbuffer[i].pm10 = -1.0;
+ pmbuffer[i].pm25 = -1.0;
}
}
+
+void init_tempbuffer(){
+ for (int i = 0; i < TEMPBUFFERSIZE; i++){
+ tempbuffer[i] = 0x8000;
+ }
+}
+
void init_uart(void) {
const uart_config_t uart_config = {
.baud_rate = 9600,
}
}
-static void send_report(uint8_t report_type){
+static void send_report(int report_cluster, int report_attribute){
ESP_LOGI(TAG, "sending report here");
esp_zb_zcl_report_attr_cmd_t des;
//ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
//des.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
- if (report_type == TEMP_REPORT){
- des.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
- des.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
- } else if (report_type == PM25_REPORT){
- des.clusterID = PM25CLUSTER;
- des.attributeID = PM25MEASURED;
- } else {
- ESP_LOGW(TAG, "undefined report type, just returning");
- return;
- }
+ des.clusterID = report_cluster;
+ des.attributeID = report_attribute;
des.cluster_role=ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
ESP_ERROR_CHECK(esp_zb_zcl_report_attr_cmd_req(&des));
- if (report_type == TEMP_REPORT){
- ESP_LOGI(TAG, "sent temp report");
- } else if (report_type == PM25_REPORT){
- ESP_LOGI(TAG, "sent pm25 report");
- }
+ ESP_LOGI(TAG, "sent report");
}
return data[30] == check_high && data[31] == check_low;
}
-float get_average_pm25(uint8_t* data, int data_size){
- int total = 0;
+aqi_data_t get_average_pm25(uint8_t* data, int data_size){
+ int pm10_total = 0;
+ int pm25_total = 0;
int count = 0;
+ aqi_data_t retval = {
+ .pm10 = -1.0,
+ .pm25 = -1.0,
+ };
+ //ESP_LOG_BUFFER_HEXDUMP(TAG, data, data_size, ESP_LOG_INFO);
char search_prefix[2] = {0x42, 0x4d};
- uint8_t* first_entry = (uint8_t*)strstr((char*)data, search_prefix);
+ uint8_t* first_entry = (uint8_t*)memmem((void*)data, data_size, search_prefix, 2);
int offset = first_entry - data;
+ if (first_entry == NULL){
+ ESP_LOGW(TAG, "invalid first entry, returning invalid data");
+ return retval;
+ }
ESP_LOGI(TAG, "first entry found at %p (offset %d)", (uint8_t*)first_entry, offset);
uint8_t* cur_entry = first_entry;
- int pm25;
+ int pm10, pm25;
while (cur_entry + 32 < data + data_size){
//printf("doing one iteration\n");
//ESP_LOG_BUFFER_HEXDUMP(TAG, cur_entry, 32, ESP_LOG_INFO);
if (verify_checksum(cur_entry)){
pm25 = (data[12] << 8) + (data[13]);
+ pm10 = (data[10] << 8) + (data[11]);
//ESP_LOGI(TAG, "pm25 val: %d", pm25);
count++;
- total += pm25;
+ pm25_total += pm25;
+ pm10_total += pm10;
} else {
ESP_LOGW(TAG, "checksum failed for uart, skipping entry");
}
cur_entry += 32;
}
- if (count == 0){
- return 0.0;
- } else {
- return ((float)total)/count;
+ if (count != 0){
+ retval.pm10 = ((float)pm10_total)/count;
+ retval.pm25 = ((float)pm25_total)/count;
}
+ print_pmdata(retval);
+ return retval;
}
+
static void monitoring_task(void* discard)
{
bool tempsetup = init_temp();
//bool tempsetup = true;
uint8_t* data = (uint8_t*) malloc(RX_BUF_SIZE+1);
+ short temp_avg = 0x8000;
int length = 0;
for(;;){
ESP_LOGI(TAG, "free heap: %"PRIu32, esp_get_free_heap_size());
//temp_list[0] += 100;
- if (tempsetup){
- temp_list[0] = get_temp();
- } else {
- ESP_LOGI(TAG, "temp not setup, skipping update");
- }
- ESP_LOGI(TAG, "current: %d", temp_list[0]);
if (zig_connected == true){
+
+ // aqi fetch/calculation/report
ESP_ERROR_CHECK(uart_get_buffered_data_len(UART_NUM_1, (size_t*)&length));
const int rxBytes = uart_read_bytes(UART_NUM_1, data, length, 100);
if (rxBytes > 0) {
data[rxBytes] = 0;
//ESP_LOGI(TAG, "Read %d bytes: '%s'", rxBytes, data);
//ESP_LOG_BUFFER_HEXDUMP(TAG, data, rxBytes, ESP_LOG_INFO);
- float cur_avg = get_average_pm25(data, rxBytes);
- ESP_LOGI(TAG, "average from last 10 seconds pm25: %f", cur_avg);
+ aqi_data_t cur_avg = get_average_pm25(data, rxBytes);
+ ESP_LOGI(TAG, "average from last 10 seconds pm10: %f", cur_avg.pm10);
+ ESP_LOGI(TAG, "average from last 10 seconds pm25: %f", cur_avg.pm25);
+
ESP_LOGI(TAG, "setting attrib value and sending, I guess");
- cur_pm25 = new_pm25_average(cur_avg);
+ cur_pm = new_pm_average(cur_avg);
+ uint16_t set_pm10 = (uint16_t)cur_pm.pm10;
+ uint16_t set_pm25 = (uint16_t)cur_pm.pm25;
+ esp_zb_zcl_set_attribute_val(HA_ESP_TEMP_ENDPOINT, PM25CLUSTER, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
+ PM10MEASURED, &set_pm10, false);
esp_zb_zcl_set_attribute_val(HA_ESP_TEMP_ENDPOINT, PM25CLUSTER, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
- PM25MEASURED, &cur_pm25, false);
- send_report(PM25_REPORT);
+ PM25MEASURED, &set_pm25, false);
+
+ send_report(PM10CLUSTER, PM10MEASURED);
+ send_report(PM25CLUSTER, PM25MEASURED);
} else {
ESP_LOGI(TAG, "Nothing seen from uart");
}
- ESP_LOGI(TAG, "setting attrib value and sending, I guess");
- esp_zb_zcl_set_attribute_val(HA_ESP_TEMP_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
- ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &temp_list[0], false);
- send_report(TEMP_REPORT);
- // reg sleep for 1 second to clear out backlog, then light sleep
- //ESP_LOGI(TAG, "light sleep starts in a second");
- vTaskDelay( pdMS_TO_TICKS(10000) );
- //ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(9000000));
- //ESP_ERROR_CHECK(esp_light_sleep_start());
+ // Temperature fetch/calculation/report
+ if (tempsetup){
+ temp_avg = new_temp_average(get_temp());
+ } else {
+ ESP_LOGI(TAG, "temp not setup, skipping update");
+ }
+ ESP_LOGI(TAG, "current: %d", temp_avg);
+
+ ESP_LOGI(TAG, "setting attrib value and sending, I guess");
+ esp_zb_zcl_set_attribute_val(HA_ESP_TEMP_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
+ ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &temp_avg, false);
+ send_report(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID);
- // now we've woken up I guess?
- ESP_LOGI(TAG, "I have worken up after sleep, looping around");
+
+ // loop around and sleep
+ //
+ // reg sleep for 1 second to clear out backlog, then light sleep
+ //ESP_LOGI(TAG, "light sleep starts in a second");
+ vTaskDelay( pdMS_TO_TICKS(10000) );
+ //ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(9000000));
+ //ESP_ERROR_CHECK(esp_light_sleep_start());
+
+ // now we've woken up I guess?
+ ESP_LOGI(TAG, "I have worken up after sleep, looping around");
} else {
ESP_LOGI(TAG, "zig not connected, skipping temp report (and staying awake)");
//esp_zb_scheduler_alarm((esp_zb_callback_t)monitoring_task, parm, 10000);
}
-static void esp_zb_read_resp_cb(esp_zb_zcl_status_t status, uint16_t cluster_id, uint16_t attr_id, esp_zb_zcl_attr_type_t attr_type, void *value)
-{
- ESP_LOGI(TAG, "Switch got read attribute response with status:%d,cluster_id:0x%x,attr_id:0x%x,value:%d,attr_type:0x%x", status, cluster_id, attr_id, *(uint8_t *)value, attr_type);
-}
-
void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct)
{
uint32_t *p_sg_p = signal_struct->p_app_signal;
uint8_t power_source[] = {0x01};
- for (int i= 0; i < 10; i++ ){
- temp_list[i] = 0x8000;
- }
/* basic cluster create with fully customized */
esp_zb_attribute_list_t *esp_zb_basic_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_BASIC);
esp_zb_basic_cluster_add_attr(esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, power_source);
short min_temp = -5500;
short max_temp = 12500;
+ uint16_t initial_pm10 = 0;
+ uint16_t initial_pm25 = 0;
// temperature cluster
esp_zb_attribute_list_t *esp_zb_temp_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT);
- esp_zb_temperature_meas_cluster_add_attr(esp_zb_temp_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &temp_list[0]);
+ esp_zb_temperature_meas_cluster_add_attr(esp_zb_temp_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &tempbuffer[0]);
esp_zb_temperature_meas_cluster_add_attr(esp_zb_temp_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, &min_temp);
esp_zb_temperature_meas_cluster_add_attr(esp_zb_temp_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, &max_temp);
esp_zb_attribute_list_t *esp_zb_pm25_cluster = esp_zb_zcl_attr_list_create(PM25CLUSTER);
- ESP_ERROR_CHECK(esp_zb_custom_cluster_add_custom_attr(esp_zb_pm25_cluster, PM25MEASURED, ESP_ZB_ZCL_ATTR_TYPE_U16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING, &cur_pm25));
+ ESP_ERROR_CHECK(esp_zb_custom_cluster_add_custom_attr(esp_zb_pm25_cluster, PM25MEASURED, ESP_ZB_ZCL_ATTR_TYPE_U16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING, &initial_pm25));
+ ESP_ERROR_CHECK(esp_zb_custom_cluster_add_custom_attr(esp_zb_pm25_cluster, PM10MEASURED, ESP_ZB_ZCL_ATTR_TYPE_U16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING, &initial_pm10));
+
/* create cluster lists for this endpoint */
esp_zb_cluster_list_t *esp_zb_cluster_list = esp_zb_zcl_cluster_list_create();
esp_zb_cluster_list_add_basic_cluster(esp_zb_cluster_list, esp_zb_basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
-
- // add all the clusters to our main cluster list
- //esp_zb_cluster_list_update_basic_cluster(esp_zb_cluster_list, esp_zb_basic_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_identify_cluster(esp_zb_cluster_list, esp_zb_identify_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_temperature_meas_cluster(esp_zb_cluster_list, esp_zb_temp_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
ESP_ERROR_CHECK(esp_zb_cluster_list_add_custom_cluster(esp_zb_cluster_list, esp_zb_pm25_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE));
esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list, HA_ESP_TEMP_ENDPOINT, ESP_ZB_AF_HA_PROFILE_ID, ESP_ZB_HA_ON_OFF_OUTPUT_DEVICE_ID);
esp_zb_device_register(esp_zb_ep_list);
- // set first pm25 val
- /*esp_zb_zcl_set_attribute_val(HA_ESP_TEMP_ENDPOINT, PM25CLUSTER, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
- PM25MEASURED, &cur_pm25, false);*/
-
- // set first temp value
- esp_zb_zcl_set_attribute_val(HA_ESP_TEMP_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
- ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &temp_list[0], false);
-
- //esp_zb_device_add_set_attr_value_cb(attr_cb);
- esp_zb_add_read_attr_resp_cb(HA_ESP_TEMP_ENDPOINT, esp_zb_read_resp_cb);
ESP_ERROR_CHECK(esp_zb_start(false));
//ESP_ERROR_CHECK(esp_zb_secur_ic_set(ESP_ZB_IC_TYPE_128, (uint8_t*)curic));
};
ESP_ERROR_CHECK(nvs_flash_init());
init_uart();
- init_pm25buffer();
+ init_pmbuffer();
+ init_tempbuffer();
/* load Zigbee light_bulb platform config to initialization */
ESP_ERROR_CHECK(esp_zb_platform_config(&config));
/* hardware related and device init */