summaryrefslogtreecommitdiff
path: root/software/main
diff options
context:
space:
mode:
authorEric Dao <eric@erickhangdao.com>2022-07-09 22:38:28 -0400
committerEric Dao <eric@erickhangdao.com>2022-07-09 22:38:28 -0400
commitcb234a53f606de8bd136b596a316e912ddf15185 (patch)
treec5f4bf00e4e7e038c24f4ff79f3c5f7af9474ca9 /software/main
parent9dd37009b3dc7d4d155f5c1a529ace46e55c8e0d (diff)
downloadmotorized_blinds-master.tar.gz
motorized_blinds-master.tar.bz2
motorized_blinds-master.zip
added licenseHEADmaster
Diffstat (limited to 'software/main')
-rw-r--r--software/main/CMakeLists.txt3
-rw-r--r--software/main/Kconfig.projbuild14
-rw-r--r--software/main/component.mk4
-rw-r--r--software/main/main.c103
-rw-r--r--software/main/sntp.c45
-rw-r--r--software/main/stepper.c99
-rw-r--r--software/main/sun.c100
-rw-r--r--software/main/wifi.c94
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