/* * Copyright 2019 by Morgan Allen * * This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International * https://creativecommons.org/licenses/by-nc/4.0/ */ #include #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/timers.h" #include "freertos/event_groups.h" #include "esp_system.h" #include "esp_log.h" #include "esp_console.h" #include "esp_sleep.h" #include "esp_vfs_dev.h" #include "nvs_flash.h" #include "esp_http_client.h" #include "driver/uart.h" #include "driver/mcpwm.h" #include "soc/mcpwm_reg.h" #include "soc/mcpwm_struct.h" #include "linenoise/linenoise.h" #include "argtable3/argtable3.h" #include "driver/gpio.h" #include "driver/spi_master.h" #include "lwip/sockets.h" #include "lwip/dns.h" #include "lwip/netdb.h" #include "mqtt_client.h" #include "esp32-wifi-manager.h" #define TAG "BTN" #define GPIO_INPUT_IO_0 33 #define GPIO_INPUT_PIN_SEL ((1ULL<client; int msg_id; switch ((esp_mqtt_event_id_t)event_id) { case MQTT_EVENT_CONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); esp_mqtt_client_subscribe(client, "espbutton/update", 0); esp_mqtt_client_subscribe(client, TOPIC_POWER_STATUS, 0); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); break; case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); break; case MQTT_EVENT_UNSUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); break; case MQTT_EVENT_PUBLISHED: ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); break; case MQTT_EVENT_DATA: ESP_LOGI(TAG, "MQTT_EVENT_DATA [topic: %.*s]", event->topic_len, event->topic); if(strncmp(event->topic, (const char*)TOPIC_POWER_STATUS, event->data_len) == 0) { ESP_LOGI(TAG, "data_len: %d", event->data_len); if(strncmp(event->data, "ON", 2) == 0) { xTimerStop(sleep_timer, portMAX_DELAY); } else if(strncmp(event->data, "OFF", 3) == 0) { reset_sleep_timer(); } } break; case MQTT_EVENT_ERROR: ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno)); } break; default: ESP_LOGI(TAG, "Other event id:%d", event->event_id); break; } } void gpio_loop() { int8_t state = -1; uint32_t io_num; esp_mqtt_client_config_t mqtt_cfg = { .uri = "mqtt://192.168.1.1", }; client = esp_mqtt_client_init(&mqtt_cfg); /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */ esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); for(;;) { if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { uint8_t level = gpio_get_level(io_num); // don't act on state level twice if(level == state) continue; // track level for duplicate state = level; EventBits_t ev_bits = xEventGroupGetBits(wm_event_group); ESP_LOGI(TAG, "gpio_loop: %d", ev_bits); if(level == 0 && (ev_bits & WIFI_CONNECTED) == 0) { ESP_LOGI(TAG, "No connectiong, connecting"); wifi_manager_scan(); continue; } printf("GPIO[%d] intr, val: %d\n", io_num, level); reset_sleep_timer(); if(level == 0) { xTimerChangePeriod(button_timer, 100 / portTICK_PERIOD_MS, portMAX_DELAY); xTimerStart(button_timer, portMAX_DELAY); } else { xTimerStop(button_timer, portMAX_DELAY); } } } } void handle_button_timer() { esp_mqtt_client_publish(client, "cmnd/tasmota_E74A79/POWER", "TOGGLE", 0, 1, 0); } void gpio_init() { gpio_config_t io_conf; io_conf.intr_type = GPIO_PIN_INTR_ANYEDGE; io_conf.mode = GPIO_MODE_INPUT; io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; io_conf.pull_down_en = 0; io_conf.pull_up_en = 1; gpio_config(&io_conf); gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); //create a queue to handle gpio event from isr gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); //start gpio task button_timer = xTimerCreate("gpio_timer", 1000, pdFALSE, (void*)NULL, handle_button_timer); sleep_timer = xTimerCreate("sleep_timer", CONFIG_SLEEP_TIMEOUT, pdFALSE, (void*)NULL, enter_sleep); reset_sleep_timer(); xTaskCreate(gpio_loop, "gpio_loop", 2048, NULL, 10, NULL); } void spi_init() { esp_err_t ret; spi_bus_config_t buscfg={ .mosi_io_num=PIN_NUM_MOSI, .sclk_io_num=PIN_NUM_CLK, .quadwp_io_num=-1, .quadhd_io_num=-1, .max_transfer_sz=120*320*2+8 }; spi_device_interface_config_t devcfg={ .clock_speed_hz=10*1000*1000, //Clock out at 10 MHz .mode=0, //SPI mode 0 .queue_size=7, //We want to be able to queue 7 transactions at a time //.pre_cb=lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line }; //Initialize the SPI bus ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1); ESP_ERROR_CHECK(ret); //Attach the LCD to the SPI bus ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi); ESP_ERROR_CHECK(ret); static spi_transaction_t trans[SPI_BUF]; int i; for (i = 0; i < SPI_BUF; i++) { memset(&trans[i], 0, sizeof(spi_transaction_t)); trans[i].length=8*4; trans[i].flags = SPI_TRANS_USE_TXDATA; } trans[1].tx_data[0] = (0b11100000 | 1); trans[1].tx_data[1] = 127; trans[1].tx_data[2] = 127; trans[1].tx_data[3] = 127; memset(&trans[SPI_BUF - 1].tx_data, 0xFF, 4); for(i = 0; i < SPI_BUF; i++) { ret = spi_device_queue_trans(spi, &trans[i], portMAX_DELAY); assert(ret==ESP_OK); } } void app_main() { esp_err_t ret; // Initialize NVS. ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { ESP_LOGI(TAG, "Erasing flash memory"); ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK( ret ); uint8_t *mac; mac = (uint8_t *)malloc(6); esp_efuse_mac_get_default(mac); id = mac[5]; ESP_LOGI(TAG, "MAC: %X:%X:%X:%X:%X:%X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); wm_event_group = wifi_manager_start(); wifi_manager_reset_store(); if(wifi_manager_ap_count() == 0) { ESP_LOGI(TAG, "Adding new AP"); if(strlen(CONFIG_WIFI_MANAGER_TEST_AP) > 0) { wifi_manager_add_ap(CONFIG_WIFI_MANAGER_TEST_AP, CONFIG_WIFI_MANAGER_TEST_PWD); } } gpio_init(); spi_init(); xTaskCreate(&led_display_loop, "led_display_loop", 4096, NULL, 6, NULL); xTaskCreate(&led_control_loop, "led_control_loop", 4096, NULL, 6, NULL); wifi_manager_scan(); while(true) { vTaskDelay(1000 / portTICK_PERIOD_MS); } };