diff options
| author | Eric Dao <eric@erickhangdao.com> | 2022-07-09 22:38:28 -0400 | 
|---|---|---|
| committer | Eric Dao <eric@erickhangdao.com> | 2022-07-09 22:38:28 -0400 | 
| commit | cb234a53f606de8bd136b596a316e912ddf15185 (patch) | |
| tree | c5f4bf00e4e7e038c24f4ff79f3c5f7af9474ca9 /software/main | |
| parent | 9dd37009b3dc7d4d155f5c1a529ace46e55c8e0d (diff) | |
| download | motorized_blinds-master.tar.gz motorized_blinds-master.tar.bz2 motorized_blinds-master.zip | |
Diffstat (limited to 'software/main')
| -rw-r--r-- | software/main/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | software/main/Kconfig.projbuild | 14 | ||||
| -rw-r--r-- | software/main/component.mk | 4 | ||||
| -rw-r--r-- | software/main/main.c | 103 | ||||
| -rw-r--r-- | software/main/sntp.c | 45 | ||||
| -rw-r--r-- | software/main/stepper.c | 99 | ||||
| -rw-r--r-- | software/main/sun.c | 100 | ||||
| -rw-r--r-- | software/main/wifi.c | 94 | 
8 files changed, 462 insertions, 0 deletions
| diff --git a/software/main/CMakeLists.txt b/software/main/CMakeLists.txt new file mode 100644 index 0000000..730c43c --- /dev/null +++ b/software/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "sun.c" "sntp.c" "wifi.c" "main.c" +                            "stepper.c" +                    INCLUDE_DIRS ".")
\ No newline at end of file diff --git a/software/main/Kconfig.projbuild b/software/main/Kconfig.projbuild new file mode 100644 index 0000000..09f282c --- /dev/null +++ b/software/main/Kconfig.projbuild @@ -0,0 +1,14 @@ +menu "Example Configuration" + +    config BLINK_GPIO +        int "Blink GPIO number" +        range 0 34 +        default 5 +        help +            GPIO number (IOxx) to blink on and off. + +            Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink. + +            GPIOs 35-39 are input-only so cannot be used as outputs. + +endmenu diff --git a/software/main/component.mk b/software/main/component.mk new file mode 100644 index 0000000..a98f634 --- /dev/null +++ b/software/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/software/main/main.c b/software/main/main.c new file mode 100644 index 0000000..f8099a3 --- /dev/null +++ b/software/main/main.c @@ -0,0 +1,103 @@ +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <time.h> +#include <sys/time.h> +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "sdkconfig.h" +#include "esp_sleep.h" + +#include "../include/stepper.h" +#include "../include/wifi.h" +#include "../include/sntp.h" +#include "../include/sun.h" + +#define us_in_h 3600000000 +#define us_in_m 60000000 +#define us_in_s 1000000 + +void app_main() { + +    // WIFI CONFIGURATION +    esp_err_t ret = nvs_flash_init(); + +    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { +      ESP_ERROR_CHECK(nvs_flash_erase()); +      ret = nvs_flash_init(); +    } +    ESP_ERROR_CHECK(ret); + +    //ESP_LOGI(WIFI_TAG, "ESP_WIFI_MODE_STA"); +    wifi_init_sta(); + +    // DATE AND TIME CONFIGURATION +    time_t now; +    struct tm time_info; +    time(&now); +    localtime_r(&now, &time_info); + +    //ESP_LOGI(SNTP_TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP."); +    obtain_time(); + +    time(&now); + +    char time_strftime_buf[64]; + +    setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1); +    tzset(); +    localtime_r(&now, &time_info); +    strftime(time_strftime_buf, sizeof(time_strftime_buf), "%c", &time_info); +    //ESP_LOGI(SNTP_TAG, "The current date/time in Toronto is: %s", time_strftime_buf); + +    // CALCULATE SUN TIME +    struct tm sun_time; + +    double sun_time_double = sun_calculation(time_info, LONGITUDE, LATITUDE); + +    //printf("sun_time is %f\n", sun_time_double); + +    sun_time.tm_hour = floor(sun_time_double); +    sun_time.tm_min = floor((sun_time_double - sun_time.tm_hour) * 60); +    sun_time.tm_sec = floor((((sun_time_double - sun_time.tm_hour) * 60) - sun_time.tm_min) * 60); + +    //TESTING STEPPER MOTOR TIMING +    // while(true) { +    //   stepper_init(); +    //   stepper_open(); +    //   stepper_close(); +    //   stepper_uninit(); +    // } + +    if(sun_time.tm_hour != time_info.tm_hour) { +      //printf("going to deep sleep\n"); +      esp_deep_sleep(us_in_h); +    } else { +      // SLEEP CONFIGURATION +      esp_sleep_enable_timer_wakeup(us_in_s); + +      // MAIN LOOP +      while(true) { +        time(&now); +        localtime_r(&now, &time_info); + +        if(time_info.tm_min < sun_time.tm_min) { +          //printf("light sleep\n"); +          esp_light_sleep_start(); +        }  +         +        if(time_info.tm_hour < 12) { +          stepper_init(); +          stepper_open(); +          stepper_uninit(); +          esp_deep_sleep(us_in_m); +        } else { +          stepper_init(); +          stepper_close(); +          stepper_uninit(); +          esp_deep_sleep(us_in_m); +        } +      } +    } +} diff --git a/software/main/sntp.c b/software/main/sntp.c new file mode 100644 index 0000000..c639a79 --- /dev/null +++ b/software/main/sntp.c @@ -0,0 +1,45 @@ +#include <string.h> +#include <time.h> +#include <sys/time.h> +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "esp_sleep.h" +#include "nvs_flash.h" +#include "esp_sntp.h" + +#include "../include/sntp.h" + +void obtain_time(void); +void initialize_sntp(void); + +void time_sync_notification_cb(struct timeval *tv) { +    ESP_LOGI(SNTP_TAG, "Notification of a time synchronization event"); +} + +void initialize_sntp(void) { +    ESP_LOGI(SNTP_TAG, "Initializing SNTP"); +    sntp_setoperatingmode(SNTP_OPMODE_POLL); +    sntp_setservername(0, "pool.ntp.org"); +    sntp_set_time_sync_notification_cb(time_sync_notification_cb); +    sntp_init(); +} + +void obtain_time(void) { +    initialize_sntp(); + +    time_t now = 0; +    struct tm timeinfo = {0}; +    int retry = 0; +    const int retry_count = 10; +    while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) { +        ESP_LOGI(SNTP_TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); +        vTaskDelay(2000 / portTICK_PERIOD_MS); +    } +    time(&now); +    localtime_r(&now, &timeinfo); +}
\ No newline at end of file diff --git a/software/main/stepper.c b/software/main/stepper.c new file mode 100644 index 0000000..71ac227 --- /dev/null +++ b/software/main/stepper.c @@ -0,0 +1,99 @@ +#include <stdio.h> +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "sdkconfig.h" + +#include "../include/stepper.h" + +// FOR L928 DRIVER +// const uint8_t half_steps_phase[8] = {0x09, 0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08}; + +// void stepper_init(struct stepper_pins_t *stepper_ptr) { +//     gpio_set_direction(stepper_ptr->pin1, GPIO_MODE_OUTPUT); +//     gpio_set_direction(stepper_ptr->pin2, GPIO_MODE_OUTPUT); +//     gpio_set_direction(stepper_ptr->pin3, GPIO_MODE_OUTPUT); +//     gpio_set_direction(stepper_ptr->pin4, GPIO_MODE_OUTPUT); + +//     printf("stepper init success\n"); +// } + +// void stepper_uninit(struct stepper_pins_t * stepper_ptr) { +//     gpio_set_direction(stepper_ptr->pin1, GPIO_MODE_INPUT); +//     gpio_set_direction(stepper_ptr->pin2, GPIO_MODE_INPUT); +//     gpio_set_direction(stepper_ptr->pin3, GPIO_MODE_INPUT); +//     gpio_set_direction(stepper_ptr->pin4, GPIO_MODE_INPUT); +// } + +// void step(struct stepper_pins_t *stepper_ptr, int step) { +//     gpio_set_level(stepper_ptr->pin1, step & 1); +//     gpio_set_level(stepper_ptr->pin3, (step & 0b10) >> 1); +//     gpio_set_level(stepper_ptr->pin2, (step & 0b100) >> 2); +//     gpio_set_level(stepper_ptr->pin4, (step & 0b1000) >> 3); +// } + +// void half_steps(struct stepper_pins_t *stepper_ptr, int steps, bool dir) { +//     int step_count; +//     int phase_index; + +//     if(dir) { +//         phase_index = 0; +//         for(step_count = 0; step_count < steps; step_count++) { +//             if(phase_index > 7) +//                 phase_index = 0; +//             step(stepper_ptr, half_steps_phase[phase_index]); +//             vTaskDelay(10 / portTICK_PERIOD_MS); +//             phase_index++; +//         } +//     } else { +//         phase_index = 7; +//         for(step_count = 0; step_count < steps; step_count++) { +//             if (phase_index < 0) +//                 phase_index = 7; +//             step(stepper_ptr, half_steps_phase[phase_index]); +//             vTaskDelay(10 / portTICK_PERIOD_MS); +//             phase_index--; +//         } +//     } +// } + +// FOR A4988 DRIVER +const uint8_t step_pin = 19; +const uint8_t dir_pin = 18; +const uint8_t en_pin = 5; + +void stepper_init(void) { +    gpio_set_direction(en_pin, GPIO_MODE_OUTPUT); +    gpio_set_level(en_pin, HIGH); +    gpio_set_direction(dir_pin, GPIO_MODE_OUTPUT); +    gpio_set_direction(step_pin, GPIO_MODE_OUTPUT); +} + +void stepper_uninit(void) { +    gpio_set_level(en_pin, HIGH); +    gpio_set_direction(en_pin, GPIO_MODE_DISABLE); +    gpio_set_direction(dir_pin, GPIO_MODE_DISABLE); +    gpio_set_direction(step_pin, GPIO_MODE_DISABLE); +} + +void stepper_open(void) { +    gpio_set_level(en_pin, LOW); +    gpio_set_level(dir_pin, HIGH); +    for(uint16_t i = 0; i < 1600; i++) { +        gpio_set_level(step_pin, HIGH); +        vTaskDelay(10 / portTICK_PERIOD_MS); +        gpio_set_level(step_pin, LOW); +        vTaskDelay(10 / portTICK_PERIOD_MS); +    } +} + +void stepper_close(void) { +    gpio_set_level(en_pin, LOW); +    gpio_set_level(dir_pin, LOW); +    for(uint16_t i = 0; i < 1600; i++) { +        gpio_set_level(step_pin, HIGH); +        vTaskDelay(10 / portTICK_PERIOD_MS); +        gpio_set_level(step_pin, LOW); +        vTaskDelay(10 / portTICK_PERIOD_MS); +    } +}
\ No newline at end of file diff --git a/software/main/sun.c b/software/main/sun.c new file mode 100644 index 0000000..44d9fa1 --- /dev/null +++ b/software/main/sun.c @@ -0,0 +1,100 @@ +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <math.h> +#include <time.h> + +#include "../include/sun.h" + +double deg_to_rad(double angle) { +    return angle * (M_PI / 180); +} + +double rad_to_deg(double angle) { +    return angle * (180 / M_PI); +} + +double sun_calculation(struct tm curr_time, double longitude, double latitude) { +    // Calulate day of the year +    int day_in_year = floor(275 * (curr_time.tm_mon + 1) / 9) -  +                        ((floor(((curr_time.tm_mon + 1) + 9) / 12)) *  +                        (1 + floor(((curr_time.tm_year + 1900) - 4 * floor((curr_time.tm_year + 1900) / 4) + 2) / 3))) +  +                        curr_time.tm_mday - 30; + +    // Longitude to hour, get approx time +    double long_hour = longitude / 15; +    double approx_time; + +    if (curr_time.tm_hour < 12) +        approx_time = day_in_year + ((6 - long_hour) / 24); +    else +        approx_time = day_in_year + ((18 - long_hour) / 24); + +    // Sun's mean anomaly +    double mean_anomaly = (0.9856 * approx_time) - 3.289; + +    // Sun's true longitude +    double true_longitude = mean_anomaly + (1.916 * sin(deg_to_rad(mean_anomaly)) +  +                            (0.02 * sin(deg_to_rad(2 * mean_anomaly)) + 282.634)); + +    // Keep longitude between [0, 360) +    if (true_longitude >= 360) +        true_longitude -= 360; +    else if (true_longitude < 0) +        true_longitude += 360; +     +    // Sun's right ascension +    double right_ascension = rad_to_deg(atan(0.91764 * tan(deg_to_rad(true_longitude)))); + +    // Keep Right Ascension between [0, 360) +    if (right_ascension >= 360) +        right_ascension -= 360; +    else if (right_ascension < 0) +        right_ascension += 360; + +    // Quadrant calibration +    int longitude_quadrant = (floor(true_longitude / 90)) * 90; +    int right_ascension_quadrant = (floor(right_ascension / 90)) * 90; + +    right_ascension += (longitude_quadrant - right_ascension_quadrant); + +    right_ascension /= 15; // convert to hours + +    // Calculate Sun's declination +    double sin_declination = 0.39782 * sin(deg_to_rad(true_longitude)); +    double cos_declination = cos(asin(sin_declination)); + +    // Calculate Sun's local hour angle +    double sun_hour; + +    double cos_hour = (-0.01454 - (sin_declination * sin(deg_to_rad(latitude)))) /  +                (cos_declination * cos(deg_to_rad(latitude))); +     +    if (curr_time.tm_hour < 12) +        sun_hour = 360 - rad_to_deg(acos(cos_hour)); +    else +        sun_hour = rad_to_deg(acos(cos_hour)); + +    sun_hour /= 15; // convert to hours + +    // Local time +    double local_mean_time = sun_hour + right_ascension - (0.06571 * approx_time) - 6.622; + +    // Adjust to UTC +    double sun_UTC = local_mean_time - long_hour; + +    // Keep Sun UTC between [0, 24) +    if (sun_UTC >= 24) +        sun_UTC -= 24; +    else if (sun_UTC < 0) +        sun_UTC += 24; + +    double sun_time = sun_UTC + LOCAL_OFFSET; +     +    if (sun_time < 0) +        return (24 + sun_time); +    else if (sun_time > 24) +        return (sun_time - 24); +    else     +        return sun_time; +}
\ No newline at end of file diff --git a/software/main/wifi.c b/software/main/wifi.c new file mode 100644 index 0000000..f319257 --- /dev/null +++ b/software/main/wifi.c @@ -0,0 +1,94 @@ +#include <string.h> +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#include "lwip/err.h" +#include "lwip/sys.h" + +#include "../include/wifi.h" + +void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { +    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { +        esp_wifi_connect(); +    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { +        if (s_retry_num < ESP_MAXIMUM_RETRY) { +            esp_wifi_connect(); +            s_retry_num++; +            ESP_LOGI(WIFI_TAG, "retry to connect to the AP"); +        } else { +            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); +        } +        ESP_LOGI(WIFI_TAG,"connect to the AP fail"); +    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { +        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; +        ESP_LOGI(WIFI_TAG, "got ip:%s", +                 ip4addr_ntoa(&event->ip_info.ip)); +        s_retry_num = 0; +        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); +    } +} + +void wifi_init_sta() { +    s_wifi_event_group = xEventGroupCreate(); + +    tcpip_adapter_init(); + +    ESP_ERROR_CHECK(esp_event_loop_create_default()); + +    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); +    ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + +    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); +    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); + +    wifi_config_t wifi_config = { +        .sta = { +            .ssid = ESP_WIFI_SSID, +            .password = ESP_WIFI_PASS, +            /* Setting a password implies station will connect to all security modes including WEP/WPA. +             * However these modes are deprecated and not advisable to be used. Incase your Access point +             * doesn't support WPA2, these mode can be enabled by commenting below line */ +	     .threshold.authmode = WIFI_AUTH_WPA2_PSK, + +            .pmf_cfg = { +                .capable = true, +                .required = false +            }, +        }, +    }; +    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); +    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); +    ESP_ERROR_CHECK(esp_wifi_start() ); + +    ESP_LOGI(WIFI_TAG, "wifi_init_sta finished."); + +    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum +     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ +    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, +            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, +            pdFALSE, +            pdFALSE, +            portMAX_DELAY); + +    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually +     * happened. */ +    if (bits & WIFI_CONNECTED_BIT) { +        ESP_LOGI(WIFI_TAG, "connected to ap SSID:%s password:%s", +                 ESP_WIFI_SSID, ESP_WIFI_PASS); +    } else if (bits & WIFI_FAIL_BIT) { +        ESP_LOGI(WIFI_TAG, "Failed to connect to SSID:%s, password:%s", +                 ESP_WIFI_SSID, ESP_WIFI_PASS); +    } else { +        ESP_LOGE(WIFI_TAG, "UNEXPECTED EVENT"); +    } + +    ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler)); +    ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler)); +    vEventGroupDelete(s_wifi_event_group); +}
\ No newline at end of file | 
