├── ChartJs
├── CMakeLists.txt
├── LICENSE
├── README.md
├── html
│ ├── error.html
│ ├── favicon.ico
│ ├── main.css
│ ├── main.js
│ └── root.html
└── main
│ ├── CMakeLists.txt
│ ├── Kconfig.projbuild
│ ├── component.mk
│ ├── idf_component.yml
│ ├── main.c
│ ├── web_client.c
│ └── web_server.c
├── EpochJs
├── CMakeLists.txt
├── LICENSE
├── README.md
├── html
│ ├── error.html
│ ├── favicon.ico
│ ├── main.css
│ ├── main.js
│ └── root.html
└── main
│ ├── CMakeLists.txt
│ ├── Kconfig.projbuild
│ ├── component.mk
│ ├── idf_component.yml
│ ├── main.c
│ ├── web_client.c
│ └── web_server.c
├── HorizontalLinearGauge
├── CMakeLists.txt
├── LICENSE
├── README.md
├── html
│ ├── error.html
│ ├── favicon.ico
│ ├── main.css
│ ├── main.js
│ └── root.html
└── main
│ ├── CMakeLists.txt
│ ├── Kconfig.projbuild
│ ├── component.mk
│ ├── idf_component.yml
│ ├── main.c
│ ├── web_client.c
│ └── web_server.c
├── LICENSE
├── PlotlyChart
├── CMakeLists.txt
├── LICENSE
├── README.md
├── html
│ ├── error.html
│ ├── favicon.ico
│ ├── main.css
│ ├── main.js
│ └── root.html
└── main
│ ├── CMakeLists.txt
│ ├── Kconfig.projbuild
│ ├── component.mk
│ ├── idf_component.yml
│ ├── main.c
│ ├── web_client.c
│ └── web_server.c
├── PlotlyGauge
├── CMakeLists.txt
├── LICENSE
├── README.md
├── html
│ ├── error.html
│ ├── favicon.ico
│ ├── main.css
│ ├── main.js
│ └── root.html
└── main
│ ├── CMakeLists.txt
│ ├── Kconfig.projbuild
│ ├── component.mk
│ ├── idf_component.yml
│ ├── main.c
│ ├── web_client.c
│ └── web_server.c
├── README.md
├── RadialGauge
├── CMakeLists.txt
├── LICENSE
├── README.md
├── html
│ ├── error.html
│ ├── favicon.ico
│ ├── main.css
│ ├── main.js
│ └── root.html
└── main
│ ├── CMakeLists.txt
│ ├── Kconfig.projbuild
│ ├── component.mk
│ ├── idf_component.yml
│ ├── main.c
│ ├── web_client.c
│ └── web_server.c
├── SevenSegment
├── CMakeLists.txt
├── LICENSE
├── README.md
├── html
│ ├── error.html
│ ├── favicon.ico
│ ├── main.css
│ ├── main.js
│ ├── root.html
│ └── seven_segment_display.js
└── main
│ ├── CMakeLists.txt
│ ├── Kconfig.projbuild
│ ├── component.mk
│ ├── idf_component.yml
│ ├── main.c
│ ├── web_client.c
│ └── web_server.c
└── VerticalLinearGauge
├── CMakeLists.txt
├── LICENSE
├── README.md
├── html
├── error.html
├── favicon.ico
├── main.css
├── main.js
└── root.html
└── main
├── CMakeLists.txt
├── Kconfig.projbuild
├── component.mk
├── idf_component.yml
├── main.c
├── web_client.c
└── web_server.c
/ChartJs/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The following five lines of boilerplate have to be in your project's
2 | # CMakeLists in this exact order for cmake to work correctly
3 | cmake_minimum_required(VERSION 3.5)
4 |
5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6 | project(chartjs-plugin-streaming)
7 |
--------------------------------------------------------------------------------
/ChartJs/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 nopnop2002
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ChartJs/README.md:
--------------------------------------------------------------------------------
1 | # Chart display using chart.js
2 | 
3 |
4 | I used [this](https://nagix.github.io/chartjs-plugin-streaming/1.9.0/) for chart display.
5 | You can easily change the chart design.
6 |
7 | Document is [here](https://www.chartjs.org/docs/latest/).
8 |
9 |
--------------------------------------------------------------------------------
/ChartJs/html/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ESP32 Error 404
5 |
6 |
7 |
8 |
9 |
10 |
11 | Error 404
12 | Unknown page. Return home.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/ChartJs/html/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nopnop2002/esp-idf-web-chart/ce073d46522b28e6a06e84bd34ece938afb5857a/ChartJs/html/favicon.ico
--------------------------------------------------------------------------------
/ChartJs/html/main.css:
--------------------------------------------------------------------------------
1 | .button{
2 | width: 100px;
3 | padding: 10px;
4 | box-sizing: border-box;
5 | border: 1px solid #68779a;
6 | background: #cbe8fa;
7 | cursor: pointer;
8 | }
9 |
--------------------------------------------------------------------------------
/ChartJs/html/main.js:
--------------------------------------------------------------------------------
1 | //document.getElementById("datetime").innerHTML = "WebSocket is not connected";
2 |
3 | var websocket = new WebSocket('ws://'+location.hostname+'/');
4 | var meter1 = 0;
5 | var meter2 = 0;
6 | var meter3 = 0;
7 |
8 | function pauseDatasetPush(name) {
9 | console.log('pauseDatasetPush');
10 | sendText(name);
11 |
12 | var button = document.getElementById("pauseDataset");
13 | button.style.backgroundColor = "lightblue";
14 | }
15 |
16 | function fixedDatasetPush(name) {
17 | console.log('fixedDatasetPush');
18 | sendText(name);
19 |
20 | var button = document.getElementById("fixedDataset");
21 | button.style.backgroundColor = "lightblue";
22 | }
23 |
24 |
25 | function resumeDatasetPush(name) {
26 | console.log('resumeDatasetPush');
27 | sendText(name);
28 |
29 | var button = document.getElementById("pauseDataset");
30 | button.style.backgroundColor = "";
31 | var button = document.getElementById("fixedDataset");
32 | button.style.backgroundColor = "";
33 | }
34 |
35 | function sendText(name) {
36 | console.log('sendText');
37 | var data = {};
38 | data["id"] = name;
39 | console.log('data=', data);
40 | json_data = JSON.stringify(data);
41 | console.log('json_data=' + json_data);
42 | websocket.send(json_data);
43 | }
44 |
45 | websocket.onopen = function(evt) {
46 | console.log('WebSocket connection opened');
47 | var data = {};
48 | data["id"] = "init";
49 | console.log('data=', data);
50 | json_data = JSON.stringify(data);
51 | console.log('json_data=' + json_data);
52 | websocket.send(json_data);
53 | //document.getElementById("datetime").innerHTML = "WebSocket is connected!";
54 | }
55 |
56 | websocket.onmessage = function(evt) {
57 | var msg = evt.data;
58 | console.log("msg=" + msg);
59 | var values = msg.split('\4'); // \4 is EOT
60 | console.log("values=" + values);
61 | switch(values[0]) {
62 | case 'HEAD':
63 | console.log("HEAD values[1]=" + values[1]);
64 | var h1 = document.getElementById( 'header' );
65 | h1.textContent = values[1];
66 | break;
67 |
68 | case 'METER':
69 | console.log("METER values[1]=" + values[1]);
70 | console.log("METER values[2]=" + values[2]);
71 | console.log("METER values[3]=" + values[3]);
72 | console.log("config=" + Object.keys(config));
73 | console.log("config.data.datasets=" + Object.keys(config.data.datasets));
74 | console.log("config.data.datasets.length=", config.data.datasets.length);
75 | console.log("config.data.datasets[0]=" + Object.keys(config.data.datasets[0]));
76 | console.log("config.data.datasets[0].label=", config.data.datasets[0].label);
77 | console.log("config.data.datasets[0].backgroundColor=", config.data.datasets[0].backgroundColor);
78 | console.log("config.data.datasets[0].borderColor=", config.data.datasets[0].borderColor);
79 | if (values[1] != "") {
80 | config.data.datasets[0].label=values[1];
81 | config.data.datasets[0].backgroundColor = color(chartColors.red).alpha(0.5).rgbString();
82 | config.data.datasets[0].borderColor = chartColors.red;
83 | meter1 = 1;
84 | }
85 | if (values[2] != "") {
86 | config.data.datasets[1].label=values[2];
87 | config.data.datasets[1].backgroundColor = color(chartColors.green).alpha(0.5).rgbString();
88 | config.data.datasets[1].borderColor = chartColors.green;
89 | meter2 = 1;
90 | }
91 | if (values[3] != "") {
92 | config.data.datasets[2].label=values[3];
93 | config.data.datasets[2].backgroundColor = color(chartColors.blue).alpha(0.5).rgbString();
94 | config.data.datasets[2].borderColor = chartColors.blue;
95 | meter3 = 1;
96 | }
97 | window.myChart.update();
98 |
99 | case 'DATA':
100 | console.log("DATA values[1]=" + values[1]);
101 | var voltage1 = parseInt(values[1], 10);
102 | var now = Date.now();
103 | window.myChart.data.datasets[0].data.push({
104 | x: now,
105 | y: voltage1
106 | });
107 | if (meter2) {
108 | console.log("DATA values[2]=" + values[2]);
109 | var voltage2 = parseInt(values[2], 10);
110 | var now = Date.now();
111 | window.myChart.data.datasets[1].data.push({
112 | x: now,
113 | y: voltage2
114 | });
115 | }
116 | if (meter3) {
117 | console.log("DATA values[3]=" + values[3]);
118 | var voltage3 = parseInt(values[3], 10);
119 | var now = Date.now();
120 | window.myChart.data.datasets[2].data.push({
121 | x: now,
122 | y: voltage3
123 | });
124 | }
125 | /*
126 | var counter = 1;
127 | window.myChart.data.datasets.forEach(function(dataset) {
128 | var val = parseInt(values[counter], 10);
129 | console.log("counter=%d val=%d", counter, val);
130 | dataset.data.push({
131 | x: now,
132 | //y: randomScalingFactor()
133 | y: val
134 | });
135 | counter++;
136 | });
137 | */
138 |
139 | default:
140 | break;
141 | }
142 | }
143 |
144 | websocket.onclose = function(evt) {
145 | console.log('Websocket connection closed');
146 | //document.getElementById("datetime").innerHTML = "WebSocket closed";
147 | }
148 |
149 | websocket.onerror = function(evt) {
150 | console.log('Websocket error: ' + evt);
151 | //document.getElementById("datetime").innerHTML = "WebSocket error????!!!1!!";
152 | }
153 |
--------------------------------------------------------------------------------
/ChartJs/html/root.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | ChartJs Chart
9 |
10 |
11 |
12 |
13 |
14 |
15 |
22 |
23 |
24 |
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/ChartJs/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "main.c" "web_server.c" "web_client.c"
2 | INCLUDE_DIRS "."
3 | EMBED_FILES "../html/error.html"
4 | "../html/favicon.ico"
5 | "../html/main.js"
6 | "../html/root.html"
7 | "../html/main.css")
8 |
--------------------------------------------------------------------------------
/ChartJs/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "Application configuration"
2 |
3 | config GPIO_RANGE_MIN
4 | int
5 | default 32 if IDF_TARGET_ESP32
6 | default 1 if IDF_TARGET_ESP32S2
7 | default 1 if IDF_TARGET_ESP32S3
8 | default 0 if IDF_TARGET_ESP32C2
9 | default 0 if IDF_TARGET_ESP32C3
10 | default 0 if IDF_TARGET_ESP32C6
11 |
12 | config GPIO_RANGE_MAX
13 | int
14 | default 39 if IDF_TARGET_ESP32
15 | default 10 if IDF_TARGET_ESP32S2
16 | default 10 if IDF_TARGET_ESP32S3
17 | default 4 if IDF_TARGET_ESP32C2
18 | default 4 if IDF_TARGET_ESP32C3
19 | default 6 if IDF_TARGET_ESP32C6
20 |
21 | menu "WiFi Setting"
22 |
23 | config ESP_WIFI_SSID
24 | string "WiFi SSID"
25 | default "myssid"
26 | help
27 | SSID (network name) to connect to.
28 |
29 | config ESP_WIFI_PASSWORD
30 | string "WiFi Password"
31 | default "mypassword"
32 | help
33 | WiFi password (WPA or WPA2) to connect to.
34 |
35 | config ESP_MAXIMUM_RETRY
36 | int "Maximum retry"
37 | default 5
38 | help
39 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
40 |
41 | config MDNS_HOSTNAME
42 | string "mDNS Hostname"
43 | default "esp32-server"
44 | help
45 | The mDNS host name used by the ESP32.
46 |
47 | endmenu
48 |
49 | menu "ADC Setting"
50 |
51 | config METER1_GPIO
52 | int "GPIO for ADC1"
53 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
54 | default 32 if IDF_TARGET_ESP32
55 | default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
56 | default 0 # C3 and others
57 | help
58 | ADC1_CHANNEL number.
59 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
60 | On the ESP32, 8 channels: GPIO32 - GPIO39.
61 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
62 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
63 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
64 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
65 |
66 | config ENABLE_METER2
67 | bool "Enable METER2"
68 | default n
69 | help
70 | Enable Meter2.
71 |
72 | config METER2_GPIO
73 | depends on ENABLE_METER2
74 | int "GPIO for METER2"
75 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
76 | default 33 if IDF_TARGET_ESP32
77 | default 2 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
78 | default 1 # C3 and others
79 | help
80 | ADC1_CHANNEL number.
81 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
82 | On the ESP32, 8 channels: GPIO32 - GPIO39.
83 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
84 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
85 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
86 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
87 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
88 |
89 | config ENABLE_METER3
90 | bool "Enable METER3"
91 | default n
92 | help
93 | Enable Meter3.
94 |
95 | config METER3_GPIO
96 | depends on ENABLE_METER3
97 | int "GPIO for METER3"
98 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
99 | default 34 if IDF_TARGET_ESP32
100 | default 3 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
101 | default 2 # C3 and others
102 | help
103 | ADC1_CHANNEL number.
104 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
105 | On the ESP32, 8 channels: GPIO32 - GPIO39.
106 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
107 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
108 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
109 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
110 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
111 |
112 | config ADC_CYCLE
113 | int "ADC measurement cycle tick"
114 | range 100 1000
115 | default 100
116 | help
117 | ADC measurement cycle tick.
118 |
119 | config ENABLE_STDOUT
120 | bool "Enable STDOUT"
121 | default n
122 | help
123 | Enable STDOUT.
124 |
125 | endmenu
126 |
127 | endmenu
128 |
129 |
--------------------------------------------------------------------------------
/ChartJs/main/component.mk:
--------------------------------------------------------------------------------
1 | COMPONENT_EMBED_FILES := ../html/error.html
2 | COMPONENT_EMBED_FILES += ../html/favicon.ico
3 | COMPONENT_EMBED_FILES += ../html/main.js
4 | COMPONENT_EMBED_FILES += ../html/root.html
5 | COMPONENT_EMBED_FILES += ../html/bulma.css
6 | COMPONENT_EMBED_FILES += ../html/main.css
7 |
--------------------------------------------------------------------------------
/ChartJs/main/idf_component.yml:
--------------------------------------------------------------------------------
1 | ## IDF Component Manager Manifest File
2 | dependencies:
3 | Molorius/esp32-websocket:
4 | git: https://github.com/Molorius/esp32-websocket
5 | espressif/mdns:
6 | version: "^1.0.3"
7 | rules:
8 | - if: "idf_version >=5.0"
9 |
--------------------------------------------------------------------------------
/ChartJs/main/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/event_groups.h"
16 | #include "freertos/message_buffer.h"
17 |
18 | #include "esp_wifi.h"
19 | #include "esp_log.h"
20 | #include "nvs_flash.h"
21 | #include "mdns.h"
22 |
23 | #include "websocket_server.h"
24 |
25 | MessageBufferHandle_t xMessageBufferToClient;
26 |
27 | /* FreeRTOS event group to signal when we are connected*/
28 | static EventGroupHandle_t s_wifi_event_group;
29 |
30 | /* The event group allows multiple bits for each event, but we only care about two events:
31 | * - we are connected to the AP with an IP
32 | * - we failed to connect after the maximum amount of retries */
33 | #define WIFI_CONNECTED_BIT BIT0
34 | #define WIFI_FAIL_BIT BIT1
35 |
36 | static const char *TAG = "main";
37 |
38 | static int s_retry_num = 0;
39 |
40 | static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
41 | {
42 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
43 | esp_wifi_connect();
44 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
45 | if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
46 | esp_wifi_connect();
47 | s_retry_num++;
48 | ESP_LOGI(TAG, "retry to connect to the AP");
49 | } else {
50 | xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
51 | }
52 | ESP_LOGI(TAG,"connect to the AP fail");
53 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
54 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
55 | ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
56 | s_retry_num = 0;
57 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
58 | }
59 | }
60 |
61 | void wifi_init_sta(void)
62 | {
63 | s_wifi_event_group = xEventGroupCreate();
64 |
65 | ESP_ERROR_CHECK(esp_netif_init());
66 |
67 | ESP_ERROR_CHECK(esp_event_loop_create_default());
68 | esp_netif_create_default_wifi_sta();
69 |
70 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
71 | ESP_ERROR_CHECK(esp_wifi_init(&cfg));
72 |
73 | esp_event_handler_instance_t instance_any_id;
74 | esp_event_handler_instance_t instance_got_ip;
75 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
76 | ESP_EVENT_ANY_ID,
77 | &event_handler,
78 | NULL,
79 | &instance_any_id));
80 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
81 | IP_EVENT_STA_GOT_IP,
82 | &event_handler,
83 | NULL,
84 | &instance_got_ip));
85 |
86 | wifi_config_t wifi_config = {
87 | .sta = {
88 | .ssid = CONFIG_ESP_WIFI_SSID,
89 | .password = CONFIG_ESP_WIFI_PASSWORD,
90 | /* Setting a password implies station will connect to all security modes including WEP/WPA.
91 | * However these modes are deprecated and not advisable to be used. Incase your Access point
92 | * doesn't support WPA2, these mode can be enabled by commenting below line */
93 | .threshold.authmode = WIFI_AUTH_WPA2_PSK,
94 |
95 | .pmf_cfg = {
96 | .capable = true,
97 | .required = false
98 | },
99 | },
100 | };
101 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
102 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
103 | ESP_ERROR_CHECK(esp_wifi_start() );
104 |
105 | ESP_LOGI(TAG, "wifi_init_sta finished.");
106 |
107 | /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
108 | * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
109 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
110 | WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
111 | pdFALSE,
112 | pdFALSE,
113 | portMAX_DELAY);
114 |
115 | /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
116 | * happened. */
117 | if (bits & WIFI_CONNECTED_BIT) {
118 | ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
119 | } else if (bits & WIFI_FAIL_BIT) {
120 | ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
121 | } else {
122 | ESP_LOGE(TAG, "UNEXPECTED EVENT");
123 | }
124 |
125 | /* The event will not be processed after unregister */
126 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
127 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
128 | vEventGroupDelete(s_wifi_event_group);
129 | }
130 |
131 | void initialise_mdns(void)
132 | {
133 | //initialize mDNS
134 | ESP_ERROR_CHECK( mdns_init() );
135 | //set mDNS hostname (required if you want to advertise services)
136 | ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
137 | ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
138 |
139 | //initialize service
140 | ESP_ERROR_CHECK( mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) );
141 |
142 | #if 0
143 | //set default mDNS instance name
144 | ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
145 | #endif
146 | }
147 |
148 | void client_task(void* pvParameters);
149 | void server_task(void* pvParameters);
150 |
151 | void app_main() {
152 | // Initialize NVS
153 | esp_err_t ret = nvs_flash_init();
154 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
155 | ESP_ERROR_CHECK(nvs_flash_erase());
156 | ret = nvs_flash_init();
157 | }
158 | ESP_ERROR_CHECK(ret);
159 |
160 | // Initialize WiFi
161 | wifi_init_sta();
162 |
163 | // Initialize mDNS
164 | initialise_mdns();
165 |
166 | // Create Message Buffer
167 | xMessageBufferToClient = xMessageBufferCreate(1024);
168 | configASSERT( xMessageBufferToClient );
169 |
170 | // Get the local IP address
171 | esp_netif_ip_info_t ip_info;
172 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
173 | char cparam0[64];
174 | sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
175 |
176 | // Start web socket server
177 | ws_server_start();
178 |
179 | // Start web server
180 | xTaskCreate(&server_task, "server_task", 1024*4, (void *)cparam0, 5, NULL);
181 |
182 | // Start web client
183 | xTaskCreate(&client_task, "client_task", 1024*4, NULL, 5, NULL);
184 |
185 | vTaskDelay(100);
186 | }
187 |
--------------------------------------------------------------------------------
/ChartJs/main/web_server.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/message_buffer.h"
16 | #include "esp_log.h"
17 |
18 | #include "websocket_server.h"
19 |
20 | static QueueHandle_t client_queue;
21 | extern MessageBufferHandle_t xMessageBufferToClient;
22 |
23 | const static int client_queue_size = 10;
24 |
25 | // handles websocket events
26 | void websocket_callback(uint8_t num,WEBSOCKET_TYPE_t type,char* msg,uint64_t len) {
27 | const static char* TAG = "websocket_callback";
28 | //int value;
29 |
30 | switch(type) {
31 | case WEBSOCKET_CONNECT:
32 | ESP_LOGI(TAG,"client %i connected!",num);
33 | break;
34 | case WEBSOCKET_DISCONNECT_EXTERNAL:
35 | ESP_LOGI(TAG,"client %i sent a disconnect message",num);
36 | break;
37 | case WEBSOCKET_DISCONNECT_INTERNAL:
38 | ESP_LOGI(TAG,"client %i was disconnected",num);
39 | break;
40 | case WEBSOCKET_DISCONNECT_ERROR:
41 | ESP_LOGI(TAG,"client %i was disconnected due to an error",num);
42 | break;
43 | case WEBSOCKET_TEXT:
44 | if(len) { // if the message length was greater than zero
45 | ESP_LOGI(TAG, "got message length %i: %s", (int)len, msg);
46 | size_t xBytesSent = xMessageBufferSendFromISR(xMessageBufferToClient, msg, len, NULL);
47 | if (xBytesSent != len) {
48 | ESP_LOGE(TAG, "xMessageBufferSend fail");
49 | }
50 | }
51 | break;
52 | case WEBSOCKET_BIN:
53 | ESP_LOGI(TAG,"client %i sent binary message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
54 | break;
55 | case WEBSOCKET_PING:
56 | ESP_LOGI(TAG,"client %i pinged us with message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
57 | break;
58 | case WEBSOCKET_PONG:
59 | ESP_LOGI(TAG,"client %i responded to the ping",num);
60 | break;
61 | }
62 | }
63 |
64 | // serves any clients
65 | static void http_server(struct netconn *conn) {
66 | const static char* TAG = "http_server";
67 | const static char HTML_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/html\n\n";
68 | const static char ERROR_HEADER[] = "HTTP/1.1 404 Not Found\nContent-type: text/html\n\n";
69 | const static char JS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\n\n";
70 | const static char CSS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/css\n\n";
71 | //const static char PNG_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/png\n\n";
72 | const static char ICO_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/x-icon\n\n";
73 | //const static char PDF_HEADER[] = "HTTP/1.1 200 OK\nContent-type: application/pdf\n\n";
74 | //const static char EVENT_HEADER[] = "HTTP/1.1 200 OK\nContent-Type: text/event-stream\nCache-Control: no-cache\nretry: 3000\n\n";
75 | struct netbuf* inbuf;
76 | static char* buf;
77 | static uint16_t buflen;
78 | static err_t err;
79 |
80 | // default page
81 | extern const uint8_t root_html_start[] asm("_binary_root_html_start");
82 | extern const uint8_t root_html_end[] asm("_binary_root_html_end");
83 | const uint32_t root_html_len = root_html_end - root_html_start;
84 |
85 | // main.js
86 | extern const uint8_t main_js_start[] asm("_binary_main_js_start");
87 | extern const uint8_t main_js_end[] asm("_binary_main_js_end");
88 | const uint32_t main_js_len = main_js_end - main_js_start;
89 |
90 | // main.css
91 | extern const uint8_t main_css_start[] asm("_binary_main_css_start");
92 | extern const uint8_t main_css_end[] asm("_binary_main_css_end");
93 | const uint32_t main_css_len = main_css_end - main_css_start;
94 |
95 | // favicon.ico
96 | extern const uint8_t favicon_ico_start[] asm("_binary_favicon_ico_start");
97 | extern const uint8_t favicon_ico_end[] asm("_binary_favicon_ico_end");
98 | const uint32_t favicon_ico_len = favicon_ico_end - favicon_ico_start;
99 |
100 | // error page
101 | extern const uint8_t error_html_start[] asm("_binary_error_html_start");
102 | extern const uint8_t error_html_end[] asm("_binary_error_html_end");
103 | const uint32_t error_html_len = error_html_end - error_html_start;
104 |
105 | netconn_set_recvtimeout(conn,1000); // allow a connection timeout of 1 second
106 | ESP_LOGI(TAG,"reading from client...");
107 | err = netconn_recv(conn, &inbuf);
108 | ESP_LOGI(TAG,"read from client");
109 | if(err==ERR_OK) {
110 | netbuf_data(inbuf, (void**)&buf, &buflen);
111 | if(buf) {
112 |
113 | ESP_LOGD(TAG, "buf=[%s]", buf);
114 | // default page
115 | if (strstr(buf,"GET / ")
116 | && !strstr(buf,"Upgrade: websocket")) {
117 | ESP_LOGI(TAG,"Sending /");
118 | netconn_write(conn, HTML_HEADER, sizeof(HTML_HEADER)-1,NETCONN_NOCOPY);
119 | netconn_write(conn, root_html_start,root_html_len,NETCONN_NOCOPY);
120 | netconn_close(conn);
121 | netconn_delete(conn);
122 | netbuf_delete(inbuf);
123 | }
124 |
125 | // default page websocket
126 | else if(strstr(buf,"GET / ")
127 | && strstr(buf,"Upgrade: websocket")) {
128 | ESP_LOGI(TAG,"Requesting websocket on /");
129 | ws_server_add_client(conn,buf,buflen,"/",websocket_callback);
130 | netbuf_delete(inbuf);
131 | }
132 |
133 | else if(strstr(buf,"GET /main.js ")) {
134 | ESP_LOGI(TAG,"Sending /main.js");
135 | netconn_write(conn, JS_HEADER, sizeof(JS_HEADER)-1,NETCONN_NOCOPY);
136 | netconn_write(conn, main_js_start, main_js_len,NETCONN_NOCOPY);
137 | netconn_close(conn);
138 | netconn_delete(conn);
139 | netbuf_delete(inbuf);
140 | }
141 |
142 | else if(strstr(buf,"GET /main.css ")) {
143 | ESP_LOGI(TAG,"Sending /main.css");
144 | netconn_write(conn, CSS_HEADER, sizeof(CSS_HEADER)-1,NETCONN_NOCOPY);
145 | netconn_write(conn, main_css_start, main_css_len,NETCONN_NOCOPY);
146 | netconn_close(conn);
147 | netconn_delete(conn);
148 | netbuf_delete(inbuf);
149 | }
150 |
151 | else if(strstr(buf,"GET /favicon.ico ")) {
152 | ESP_LOGI(TAG,"Sending favicon.ico");
153 | netconn_write(conn,ICO_HEADER,sizeof(ICO_HEADER)-1,NETCONN_NOCOPY);
154 | netconn_write(conn,favicon_ico_start,favicon_ico_len,NETCONN_NOCOPY);
155 | netconn_close(conn);
156 | netconn_delete(conn);
157 | netbuf_delete(inbuf);
158 | }
159 |
160 | else if(strstr(buf,"GET /")) {
161 | ESP_LOGE(TAG,"Unknown request, sending error page: %s",buf);
162 | netconn_write(conn, ERROR_HEADER, sizeof(ERROR_HEADER)-1,NETCONN_NOCOPY);
163 | netconn_write(conn, error_html_start, error_html_len,NETCONN_NOCOPY);
164 | netconn_close(conn);
165 | netconn_delete(conn);
166 | netbuf_delete(inbuf);
167 | }
168 |
169 | else {
170 | ESP_LOGE(TAG,"Unknown request");
171 | netconn_close(conn);
172 | netconn_delete(conn);
173 | netbuf_delete(inbuf);
174 | }
175 | }
176 | else {
177 | ESP_LOGI(TAG,"Unknown request (empty?...)");
178 | netconn_close(conn);
179 | netconn_delete(conn);
180 | netbuf_delete(inbuf);
181 | }
182 | }
183 | else { // if err==ERR_OK
184 | ESP_LOGI(TAG,"error on read, closing connection");
185 | netconn_close(conn);
186 | netconn_delete(conn);
187 | netbuf_delete(inbuf);
188 | }
189 | }
190 |
191 | // receives clients from queue, handles them
192 | void server_handle_task(void* pvParameters) {
193 | const static char* TAG = "server_handle_task";
194 | struct netconn* conn;
195 | ESP_LOGI(TAG,"task starting");
196 | for(;;) {
197 | xQueueReceive(client_queue,&conn,portMAX_DELAY);
198 | if(!conn) continue;
199 | http_server(conn);
200 | }
201 | vTaskDelete(NULL);
202 | }
203 |
204 | // handles clients when they first connect. passes to a queue
205 | void server_task(void* pvParameters) {
206 | const static char* TAG = "server_task";
207 | char *task_parameter = (char *)pvParameters;
208 | ESP_LOGI(TAG, "Start task_parameter=%s", task_parameter);
209 | char url[64];
210 | sprintf(url, "http://%s", task_parameter);
211 | ESP_LOGI(TAG, "Starting server on %s", url);
212 |
213 | struct netconn *conn, *newconn;
214 | static err_t err;
215 | client_queue = xQueueCreate(client_queue_size,sizeof(struct netconn*));
216 | configASSERT( client_queue );
217 |
218 |
219 | UBaseType_t PriorityGet = uxTaskPriorityGet(NULL);
220 | ESP_LOGI(TAG, "PriorityGet=%d", PriorityGet);
221 | xTaskCreate(&server_handle_task, "server_handle_task", 1024*3, NULL, PriorityGet, NULL);
222 |
223 |
224 | conn = netconn_new(NETCONN_TCP);
225 | netconn_bind(conn,NULL,80);
226 | netconn_listen(conn);
227 | ESP_LOGI(TAG,"server listening");
228 | do {
229 | err = netconn_accept(conn, &newconn);
230 | ESP_LOGI(TAG,"new client");
231 | if(err == ERR_OK) {
232 | xQueueSendToBack(client_queue,&newconn,portMAX_DELAY);
233 | //http_server(newconn);
234 | }
235 | } while(err == ERR_OK);
236 | netconn_close(conn);
237 | netconn_delete(conn);
238 | ESP_LOGE(TAG,"task ending, rebooting board");
239 | esp_restart();
240 | }
241 |
--------------------------------------------------------------------------------
/EpochJs/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The following five lines of boilerplate have to be in your project's
2 | # CMakeLists in this exact order for cmake to work correctly
3 | cmake_minimum_required(VERSION 3.5)
4 |
5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6 | project(web-analog)
7 |
--------------------------------------------------------------------------------
/EpochJs/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 nopnop2002
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/EpochJs/README.md:
--------------------------------------------------------------------------------
1 | # Chart display using epoch.js
2 | 
3 |
4 | I used [this](https://epochjs.github.io/epoch/real-time/) for chart display.
5 | You can easily change the chart design.
6 |
7 |
8 |
--------------------------------------------------------------------------------
/EpochJs/html/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ESP32 Error 404
5 |
6 |
7 |
8 |
9 |
10 |
11 | Error 404
12 | Unknown page. Return home.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/EpochJs/html/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nopnop2002/esp-idf-web-chart/ce073d46522b28e6a06e84bd34ece938afb5857a/EpochJs/html/favicon.ico
--------------------------------------------------------------------------------
/EpochJs/html/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | Your favorite style is defined here.
3 | */
4 |
--------------------------------------------------------------------------------
/EpochJs/html/main.js:
--------------------------------------------------------------------------------
1 | //document.getElementById("datetime").innerHTML = "WebSocket is not connected";
2 |
3 | var websocket = new WebSocket('ws://'+location.hostname+'/');
4 | var meter1 = 0;
5 | var meter2 = 0;
6 | var meter3 = 0;
7 |
8 |
9 | /*
10 | function sendText(name) {
11 | console.log('sendText');
12 | var data = {};
13 | data["id"] = name;
14 | console.log('data=', data);
15 | json_data = JSON.stringify(data);
16 | console.log('json_data=' + json_data);
17 | websocket.send(json_data);
18 | }
19 | */
20 |
21 | websocket.onopen = function(evt) {
22 | console.log('WebSocket connection opened');
23 | var data = {};
24 | data["id"] = "init";
25 | console.log('data=', data);
26 | json_data = JSON.stringify(data);
27 | console.log('json_data=' + json_data);
28 | websocket.send(json_data);
29 | //document.getElementById("datetime").innerHTML = "WebSocket is connected!";
30 | }
31 |
32 | websocket.onmessage = function(evt) {
33 | var msg = evt.data;
34 | console.log("msg=" + msg);
35 | var values = msg.split('\4'); // \4 is EOT
36 | //console.log("values=" + values);
37 | switch(values[0]) {
38 | case 'HEAD':
39 | console.log("HEAD values[1]=" + values[1]);
40 | var h1 = document.getElementById( 'header' );
41 | h1.textContent = values[1];
42 | break;
43 |
44 | case 'METER':
45 | //console.log("gauge1=" + Object.keys(gauge1.options));
46 | //console.log("gauge1.options.units=" + gauge1.options.units);
47 | console.log("METER values[1]=" + values[1]);
48 | console.log("METER values[2]=" + values[2]);
49 | console.log("METER values[3]=" + values[3]);
50 | if (values[1] != "") {
51 | document.getElementById("label1").innerText = values[1] + " [mV]";
52 | meter1 = 1;
53 | }
54 | if (values[2] != "") {
55 | document.getElementById("label2").innerText = values[2] + " [mV]";
56 | meter2 = 1;
57 | } else {
58 | document.getElementById("label2").style.display ="none";
59 | document.getElementById("chart2").style.display ="none";
60 | }
61 | if (values[3] != "") {
62 | document.getElementById("label3").innerText = values[3] + " [mV]";
63 | meter3 = 1;
64 | } else {
65 | document.getElementById("label3").style.display ="none";
66 | document.getElementById("chart3").style.display ="none";
67 | }
68 | break;
69 |
70 | case 'DATA':
71 | console.log("DATA values[1]=" + values[1]);
72 | var timeVal = getChartTime();
73 | var voltage1 = parseInt(values[1], 10);
74 | // Set line color
75 | var catname = "category1";
76 | chart1.getVisibleLayers()[0].className = "layer " + catname;
77 | chart1.push([ {time: timeVal, y: voltage1} ]);
78 | if (meter2) {
79 | console.log("DATA values[2]=" + values[2]);
80 | var voltage2 = parseInt(values[2], 10);
81 | // Set line color
82 | var catname = "category2";
83 | chart2.getVisibleLayers()[0].className = "layer " + catname;
84 | chart2.push([ {time: timeVal, y: voltage2} ]);
85 | }
86 | if (meter3) {
87 | console.log("DATA values[3]=" + values[3]);
88 | var voltage3 = parseInt(values[3], 10);
89 | // Set line color
90 | var catname = "category3";
91 | chart3.getVisibleLayers()[0].className = "layer " + catname;
92 | chart3.push([ {time: timeVal, y: voltage3} ]);
93 | }
94 | break;
95 |
96 | default:
97 | break;
98 | }
99 | }
100 |
101 | websocket.onclose = function(evt) {
102 | console.log('Websocket connection closed');
103 | //document.getElementById("datetime").innerHTML = "WebSocket closed";
104 | }
105 |
106 | websocket.onerror = function(evt) {
107 | console.log('Websocket error: ' + evt);
108 | //document.getElementById("datetime").innerHTML = "WebSocket error????!!!1!!";
109 | }
110 |
--------------------------------------------------------------------------------
/EpochJs/html/root.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Epoch Chart
11 |
12 |
13 |
14 |
15 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/EpochJs/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "main.c" "web_server.c" "web_client.c"
2 | INCLUDE_DIRS "."
3 | EMBED_FILES "../html/error.html"
4 | "../html/favicon.ico"
5 | "../html/main.js"
6 | "../html/root.html"
7 | "../html/main.css")
8 |
--------------------------------------------------------------------------------
/EpochJs/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "Application configuration"
2 |
3 | config GPIO_RANGE_MIN
4 | int
5 | default 32 if IDF_TARGET_ESP32
6 | default 1 if IDF_TARGET_ESP32S2
7 | default 1 if IDF_TARGET_ESP32S3
8 | default 0 if IDF_TARGET_ESP32C2
9 | default 0 if IDF_TARGET_ESP32C3
10 | default 0 if IDF_TARGET_ESP32C6
11 |
12 | config GPIO_RANGE_MAX
13 | int
14 | default 39 if IDF_TARGET_ESP32
15 | default 10 if IDF_TARGET_ESP32S2
16 | default 10 if IDF_TARGET_ESP32S3
17 | default 4 if IDF_TARGET_ESP32C2
18 | default 4 if IDF_TARGET_ESP32C3
19 | default 6 if IDF_TARGET_ESP32C6
20 |
21 | menu "WiFi Setting"
22 |
23 | config ESP_WIFI_SSID
24 | string "WiFi SSID"
25 | default "myssid"
26 | help
27 | SSID (network name) to connect to.
28 |
29 | config ESP_WIFI_PASSWORD
30 | string "WiFi Password"
31 | default "mypassword"
32 | help
33 | WiFi password (WPA or WPA2) to connect to.
34 |
35 | config ESP_MAXIMUM_RETRY
36 | int "Maximum retry"
37 | default 5
38 | help
39 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
40 |
41 | config MDNS_HOSTNAME
42 | string "mDNS Hostname"
43 | default "esp32-server"
44 | help
45 | The mDNS host name used by the ESP32.
46 |
47 | endmenu
48 |
49 | menu "ADC Setting"
50 |
51 | config METER1_GPIO
52 | int "GPIO for ADC1"
53 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
54 | default 32 if IDF_TARGET_ESP32
55 | default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
56 | default 0 # C3 and others
57 | help
58 | ADC1_CHANNEL number.
59 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
60 | On the ESP32, 8 channels: GPIO32 - GPIO39.
61 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
62 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
63 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
64 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
65 |
66 | config ENABLE_METER2
67 | bool "Enable METER2"
68 | default n
69 | help
70 | Enable Meter2.
71 |
72 | config METER2_GPIO
73 | depends on ENABLE_METER2
74 | int "GPIO for METER2"
75 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
76 | default 33 if IDF_TARGET_ESP32
77 | default 2 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
78 | default 1 # C3 and others
79 | help
80 | ADC1_CHANNEL number.
81 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
82 | On the ESP32, 8 channels: GPIO32 - GPIO39.
83 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
84 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
85 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
86 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
87 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
88 |
89 | config ENABLE_METER3
90 | bool "Enable METER3"
91 | default n
92 | help
93 | Enable Meter3.
94 |
95 | config METER3_GPIO
96 | depends on ENABLE_METER3
97 | int "GPIO for METER3"
98 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
99 | default 34 if IDF_TARGET_ESP32
100 | default 3 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
101 | default 2 # C3 and others
102 | help
103 | ADC1_CHANNEL number.
104 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
105 | On the ESP32, 8 channels: GPIO32 - GPIO39.
106 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
107 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
108 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
109 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
110 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
111 |
112 | config ADC_CYCLE
113 | int "ADC measurement cycle tick"
114 | range 100 1000
115 | default 100
116 | help
117 | ADC measurement cycle tick.
118 |
119 | config ENABLE_STDOUT
120 | bool "Enable STDOUT"
121 | default n
122 | help
123 | Enable STDOUT.
124 |
125 | endmenu
126 |
127 | endmenu
128 |
129 |
--------------------------------------------------------------------------------
/EpochJs/main/component.mk:
--------------------------------------------------------------------------------
1 | COMPONENT_EMBED_FILES := ../html/error.html
2 | COMPONENT_EMBED_FILES += ../html/favicon.ico
3 | COMPONENT_EMBED_FILES += ../html/main.js
4 | COMPONENT_EMBED_FILES += ../html/root.html
5 | COMPONENT_EMBED_FILES += ../html/bulma.css
6 | COMPONENT_EMBED_FILES += ../html/main.css
7 |
--------------------------------------------------------------------------------
/EpochJs/main/idf_component.yml:
--------------------------------------------------------------------------------
1 | ## IDF Component Manager Manifest File
2 | dependencies:
3 | Molorius/esp32-websocket:
4 | git: https://github.com/Molorius/esp32-websocket
5 | espressif/mdns:
6 | version: "^1.0.3"
7 | rules:
8 | - if: "idf_version >=5.0"
9 |
--------------------------------------------------------------------------------
/EpochJs/main/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/event_groups.h"
16 | #include "freertos/message_buffer.h"
17 |
18 | #include "esp_wifi.h"
19 | #include "esp_log.h"
20 | #include "nvs_flash.h"
21 | #include "mdns.h"
22 |
23 | #include "websocket_server.h"
24 |
25 | MessageBufferHandle_t xMessageBufferToClient;
26 |
27 | /* FreeRTOS event group to signal when we are connected*/
28 | static EventGroupHandle_t s_wifi_event_group;
29 |
30 | /* The event group allows multiple bits for each event, but we only care about two events:
31 | * - we are connected to the AP with an IP
32 | * - we failed to connect after the maximum amount of retries */
33 | #define WIFI_CONNECTED_BIT BIT0
34 | #define WIFI_FAIL_BIT BIT1
35 |
36 | static const char *TAG = "main";
37 |
38 | static int s_retry_num = 0;
39 |
40 | static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
41 | {
42 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
43 | esp_wifi_connect();
44 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
45 | if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
46 | esp_wifi_connect();
47 | s_retry_num++;
48 | ESP_LOGI(TAG, "retry to connect to the AP");
49 | } else {
50 | xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
51 | }
52 | ESP_LOGI(TAG,"connect to the AP fail");
53 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
54 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
55 | ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
56 | s_retry_num = 0;
57 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
58 | }
59 | }
60 |
61 | void wifi_init_sta(void)
62 | {
63 | s_wifi_event_group = xEventGroupCreate();
64 |
65 | ESP_ERROR_CHECK(esp_netif_init());
66 |
67 | ESP_ERROR_CHECK(esp_event_loop_create_default());
68 | esp_netif_create_default_wifi_sta();
69 |
70 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
71 | ESP_ERROR_CHECK(esp_wifi_init(&cfg));
72 |
73 | esp_event_handler_instance_t instance_any_id;
74 | esp_event_handler_instance_t instance_got_ip;
75 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
76 | ESP_EVENT_ANY_ID,
77 | &event_handler,
78 | NULL,
79 | &instance_any_id));
80 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
81 | IP_EVENT_STA_GOT_IP,
82 | &event_handler,
83 | NULL,
84 | &instance_got_ip));
85 |
86 | wifi_config_t wifi_config = {
87 | .sta = {
88 | .ssid = CONFIG_ESP_WIFI_SSID,
89 | .password = CONFIG_ESP_WIFI_PASSWORD,
90 | /* Setting a password implies station will connect to all security modes including WEP/WPA.
91 | * However these modes are deprecated and not advisable to be used. Incase your Access point
92 | * doesn't support WPA2, these mode can be enabled by commenting below line */
93 | .threshold.authmode = WIFI_AUTH_WPA2_PSK,
94 |
95 | .pmf_cfg = {
96 | .capable = true,
97 | .required = false
98 | },
99 | },
100 | };
101 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
102 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
103 | ESP_ERROR_CHECK(esp_wifi_start() );
104 |
105 | ESP_LOGI(TAG, "wifi_init_sta finished.");
106 |
107 | /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
108 | * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
109 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
110 | WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
111 | pdFALSE,
112 | pdFALSE,
113 | portMAX_DELAY);
114 |
115 | /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
116 | * happened. */
117 | if (bits & WIFI_CONNECTED_BIT) {
118 | ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
119 | } else if (bits & WIFI_FAIL_BIT) {
120 | ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
121 | } else {
122 | ESP_LOGE(TAG, "UNEXPECTED EVENT");
123 | }
124 |
125 | /* The event will not be processed after unregister */
126 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
127 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
128 | vEventGroupDelete(s_wifi_event_group);
129 | }
130 |
131 | void initialise_mdns(void)
132 | {
133 | //initialize mDNS
134 | ESP_ERROR_CHECK( mdns_init() );
135 | //set mDNS hostname (required if you want to advertise services)
136 | ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
137 | ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
138 |
139 | //initialize service
140 | ESP_ERROR_CHECK( mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) );
141 |
142 | #if 0
143 | //set default mDNS instance name
144 | ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
145 | #endif
146 | }
147 |
148 | void client_task(void* pvParameters);
149 | void server_task(void* pvParameters);
150 |
151 | void app_main() {
152 | // Initialize NVS
153 | esp_err_t ret = nvs_flash_init();
154 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
155 | ESP_ERROR_CHECK(nvs_flash_erase());
156 | ret = nvs_flash_init();
157 | }
158 | ESP_ERROR_CHECK(ret);
159 |
160 | // Initialize WiFi
161 | wifi_init_sta();
162 |
163 | // Initialize mDNS
164 | initialise_mdns();
165 |
166 | // Create Message Buffer
167 | xMessageBufferToClient = xMessageBufferCreate(1024);
168 | configASSERT( xMessageBufferToClient );
169 |
170 | // Get the local IP address
171 | esp_netif_ip_info_t ip_info;
172 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
173 | char cparam0[64];
174 | sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
175 |
176 | // Start web socket server
177 | ws_server_start();
178 |
179 | // Start web server
180 | xTaskCreate(&server_task, "server_task", 1024*4, (void *)cparam0, 5, NULL);
181 |
182 | // Start web client
183 | xTaskCreate(&client_task, "client_task", 1024*4, NULL, 5, NULL);
184 |
185 | vTaskDelay(100);
186 | }
187 |
--------------------------------------------------------------------------------
/EpochJs/main/web_server.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/message_buffer.h"
16 | #include "esp_log.h"
17 |
18 | #include "websocket_server.h"
19 |
20 | static QueueHandle_t client_queue;
21 | extern MessageBufferHandle_t xMessageBufferToClient;
22 |
23 | const static int client_queue_size = 10;
24 |
25 | // handles websocket events
26 | void websocket_callback(uint8_t num,WEBSOCKET_TYPE_t type,char* msg,uint64_t len) {
27 | const static char* TAG = "websocket_callback";
28 | //int value;
29 |
30 | switch(type) {
31 | case WEBSOCKET_CONNECT:
32 | ESP_LOGI(TAG,"client %i connected!",num);
33 | break;
34 | case WEBSOCKET_DISCONNECT_EXTERNAL:
35 | ESP_LOGI(TAG,"client %i sent a disconnect message",num);
36 | break;
37 | case WEBSOCKET_DISCONNECT_INTERNAL:
38 | ESP_LOGI(TAG,"client %i was disconnected",num);
39 | break;
40 | case WEBSOCKET_DISCONNECT_ERROR:
41 | ESP_LOGI(TAG,"client %i was disconnected due to an error",num);
42 | break;
43 | case WEBSOCKET_TEXT:
44 | if(len) { // if the message length was greater than zero
45 | ESP_LOGI(TAG, "got message length %i: %s", (int)len, msg);
46 | size_t xBytesSent = xMessageBufferSendFromISR(xMessageBufferToClient, msg, len, NULL);
47 | if (xBytesSent != len) {
48 | ESP_LOGE(TAG, "xMessageBufferSend fail");
49 | }
50 | }
51 | break;
52 | case WEBSOCKET_BIN:
53 | ESP_LOGI(TAG,"client %i sent binary message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
54 | break;
55 | case WEBSOCKET_PING:
56 | ESP_LOGI(TAG,"client %i pinged us with message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
57 | break;
58 | case WEBSOCKET_PONG:
59 | ESP_LOGI(TAG,"client %i responded to the ping",num);
60 | break;
61 | }
62 | }
63 |
64 | // serves any clients
65 | static void http_server(struct netconn *conn) {
66 | const static char* TAG = "http_server";
67 | const static char HTML_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/html\n\n";
68 | const static char ERROR_HEADER[] = "HTTP/1.1 404 Not Found\nContent-type: text/html\n\n";
69 | const static char JS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\n\n";
70 | const static char CSS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/css\n\n";
71 | //const static char PNG_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/png\n\n";
72 | const static char ICO_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/x-icon\n\n";
73 | //const static char PDF_HEADER[] = "HTTP/1.1 200 OK\nContent-type: application/pdf\n\n";
74 | //const static char EVENT_HEADER[] = "HTTP/1.1 200 OK\nContent-Type: text/event-stream\nCache-Control: no-cache\nretry: 3000\n\n";
75 | struct netbuf* inbuf;
76 | static char* buf;
77 | static uint16_t buflen;
78 | static err_t err;
79 |
80 | // default page
81 | extern const uint8_t root_html_start[] asm("_binary_root_html_start");
82 | extern const uint8_t root_html_end[] asm("_binary_root_html_end");
83 | const uint32_t root_html_len = root_html_end - root_html_start;
84 |
85 | // main.js
86 | extern const uint8_t main_js_start[] asm("_binary_main_js_start");
87 | extern const uint8_t main_js_end[] asm("_binary_main_js_end");
88 | const uint32_t main_js_len = main_js_end - main_js_start;
89 |
90 | // main.css
91 | extern const uint8_t main_css_start[] asm("_binary_main_css_start");
92 | extern const uint8_t main_css_end[] asm("_binary_main_css_end");
93 | const uint32_t main_css_len = main_css_end - main_css_start;
94 |
95 | // favicon.ico
96 | extern const uint8_t favicon_ico_start[] asm("_binary_favicon_ico_start");
97 | extern const uint8_t favicon_ico_end[] asm("_binary_favicon_ico_end");
98 | const uint32_t favicon_ico_len = favicon_ico_end - favicon_ico_start;
99 |
100 | // error page
101 | extern const uint8_t error_html_start[] asm("_binary_error_html_start");
102 | extern const uint8_t error_html_end[] asm("_binary_error_html_end");
103 | const uint32_t error_html_len = error_html_end - error_html_start;
104 |
105 | netconn_set_recvtimeout(conn,1000); // allow a connection timeout of 1 second
106 | ESP_LOGI(TAG,"reading from client...");
107 | err = netconn_recv(conn, &inbuf);
108 | ESP_LOGI(TAG,"read from client");
109 | if(err==ERR_OK) {
110 | netbuf_data(inbuf, (void**)&buf, &buflen);
111 | if(buf) {
112 |
113 | ESP_LOGD(TAG, "buf=[%s]", buf);
114 | // default page
115 | if (strstr(buf,"GET / ")
116 | && !strstr(buf,"Upgrade: websocket")) {
117 | ESP_LOGI(TAG,"Sending /");
118 | netconn_write(conn, HTML_HEADER, sizeof(HTML_HEADER)-1,NETCONN_NOCOPY);
119 | netconn_write(conn, root_html_start,root_html_len,NETCONN_NOCOPY);
120 | netconn_close(conn);
121 | netconn_delete(conn);
122 | netbuf_delete(inbuf);
123 | }
124 |
125 | // default page websocket
126 | else if(strstr(buf,"GET / ")
127 | && strstr(buf,"Upgrade: websocket")) {
128 | ESP_LOGI(TAG,"Requesting websocket on /");
129 | ws_server_add_client(conn,buf,buflen,"/",websocket_callback);
130 | netbuf_delete(inbuf);
131 | }
132 |
133 | else if(strstr(buf,"GET /main.js ")) {
134 | ESP_LOGI(TAG,"Sending /main.js");
135 | netconn_write(conn, JS_HEADER, sizeof(JS_HEADER)-1,NETCONN_NOCOPY);
136 | netconn_write(conn, main_js_start, main_js_len,NETCONN_NOCOPY);
137 | netconn_close(conn);
138 | netconn_delete(conn);
139 | netbuf_delete(inbuf);
140 | }
141 |
142 | else if(strstr(buf,"GET /main.css ")) {
143 | ESP_LOGI(TAG,"Sending /main.css");
144 | netconn_write(conn, CSS_HEADER, sizeof(CSS_HEADER)-1,NETCONN_NOCOPY);
145 | netconn_write(conn, main_css_start, main_css_len,NETCONN_NOCOPY);
146 | netconn_close(conn);
147 | netconn_delete(conn);
148 | netbuf_delete(inbuf);
149 | }
150 |
151 | else if(strstr(buf,"GET /favicon.ico ")) {
152 | ESP_LOGI(TAG,"Sending favicon.ico");
153 | netconn_write(conn,ICO_HEADER,sizeof(ICO_HEADER)-1,NETCONN_NOCOPY);
154 | netconn_write(conn,favicon_ico_start,favicon_ico_len,NETCONN_NOCOPY);
155 | netconn_close(conn);
156 | netconn_delete(conn);
157 | netbuf_delete(inbuf);
158 | }
159 |
160 | else if(strstr(buf,"GET /")) {
161 | ESP_LOGE(TAG,"Unknown request, sending error page: %s",buf);
162 | netconn_write(conn, ERROR_HEADER, sizeof(ERROR_HEADER)-1,NETCONN_NOCOPY);
163 | netconn_write(conn, error_html_start, error_html_len,NETCONN_NOCOPY);
164 | netconn_close(conn);
165 | netconn_delete(conn);
166 | netbuf_delete(inbuf);
167 | }
168 |
169 | else {
170 | ESP_LOGE(TAG,"Unknown request");
171 | netconn_close(conn);
172 | netconn_delete(conn);
173 | netbuf_delete(inbuf);
174 | }
175 | }
176 | else {
177 | ESP_LOGI(TAG,"Unknown request (empty?...)");
178 | netconn_close(conn);
179 | netconn_delete(conn);
180 | netbuf_delete(inbuf);
181 | }
182 | }
183 | else { // if err==ERR_OK
184 | ESP_LOGI(TAG,"error on read, closing connection");
185 | netconn_close(conn);
186 | netconn_delete(conn);
187 | netbuf_delete(inbuf);
188 | }
189 | }
190 |
191 | // receives clients from queue, handles them
192 | void server_handle_task(void* pvParameters) {
193 | const static char* TAG = "server_handle_task";
194 | struct netconn* conn;
195 | ESP_LOGI(TAG,"task starting");
196 | for(;;) {
197 | xQueueReceive(client_queue,&conn,portMAX_DELAY);
198 | if(!conn) continue;
199 | http_server(conn);
200 | }
201 | vTaskDelete(NULL);
202 | }
203 |
204 | // handles clients when they first connect. passes to a queue
205 | void server_task(void* pvParameters) {
206 | const static char* TAG = "server_task";
207 | char *task_parameter = (char *)pvParameters;
208 | ESP_LOGI(TAG, "Start task_parameter=%s", task_parameter);
209 | char url[64];
210 | sprintf(url, "http://%s", task_parameter);
211 | ESP_LOGI(TAG, "Starting server on %s", url);
212 |
213 | struct netconn *conn, *newconn;
214 | static err_t err;
215 | client_queue = xQueueCreate(client_queue_size,sizeof(struct netconn*));
216 | configASSERT( client_queue );
217 |
218 |
219 | UBaseType_t PriorityGet = uxTaskPriorityGet(NULL);
220 | ESP_LOGI(TAG, "PriorityGet=%d", PriorityGet);
221 | xTaskCreate(&server_handle_task, "server_handle_task", 1024*3, NULL, PriorityGet, NULL);
222 |
223 |
224 | conn = netconn_new(NETCONN_TCP);
225 | netconn_bind(conn,NULL,80);
226 | netconn_listen(conn);
227 | ESP_LOGI(TAG,"server listening");
228 | do {
229 | err = netconn_accept(conn, &newconn);
230 | ESP_LOGI(TAG,"new client");
231 | if(err == ERR_OK) {
232 | xQueueSendToBack(client_queue,&newconn,portMAX_DELAY);
233 | //http_server(newconn);
234 | }
235 | } while(err == ERR_OK);
236 | netconn_close(conn);
237 | netconn_delete(conn);
238 | ESP_LOGE(TAG,"task ending, rebooting board");
239 | esp_restart();
240 | }
241 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The following five lines of boilerplate have to be in your project's
2 | # CMakeLists in this exact order for cmake to work correctly
3 | cmake_minimum_required(VERSION 3.5)
4 |
5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6 | project(web-analog)
7 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 nopnop2002
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/README.md:
--------------------------------------------------------------------------------
1 | # Horizontal Linear Gauge display using Canvas Gauge
2 | 
3 |
4 | I used [this](https://canvas-gauges.com/) for gauge display.
5 | You can easily change the gauge design.
6 |
7 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/html/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ESP32 Error 404
5 |
6 |
7 |
8 |
9 |
10 |
11 | Error 404
12 | Unknown page. Return home.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/html/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nopnop2002/esp-idf-web-chart/ce073d46522b28e6a06e84bd34ece938afb5857a/HorizontalLinearGauge/html/favicon.ico
--------------------------------------------------------------------------------
/HorizontalLinearGauge/html/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | Your favorite style is defined here.
3 | */
4 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/html/main.js:
--------------------------------------------------------------------------------
1 | //document.getElementById("datetime").innerHTML = "WebSocket is not connected";
2 |
3 | var websocket = new WebSocket('ws://'+location.hostname+'/');
4 | var meter1 = 0;
5 | var meter2 = 0;
6 | var meter3 = 0;
7 |
8 |
9 | function sendText(name) {
10 | console.log('sendText');
11 | var data = {};
12 | data["id"] = name;
13 | console.log('data=', data);
14 | json_data = JSON.stringify(data);
15 | console.log('json_data=' + json_data);
16 | websocket.send(json_data);
17 | }
18 |
19 | websocket.onopen = function(evt) {
20 | console.log('WebSocket connection opened');
21 | var data = {};
22 | data["id"] = "init";
23 | console.log('data=', data);
24 | json_data = JSON.stringify(data);
25 | console.log('json_data=' + json_data);
26 | websocket.send(json_data);
27 | //document.getElementById("datetime").innerHTML = "WebSocket is connected!";
28 | }
29 |
30 | websocket.onmessage = function(evt) {
31 | var msg = evt.data;
32 | console.log("msg=" + msg);
33 | var values = msg.split('\4'); // \4 is EOT
34 | //console.log("values=" + values);
35 | switch(values[0]) {
36 | case 'HEAD':
37 | console.log("HEAD values[1]=" + values[1]);
38 | var h1 = document.getElementById( 'header' );
39 | h1.textContent = values[1];
40 | break;
41 |
42 | case 'METER':
43 | //console.log("gauge1=" + Object.keys(gauge1.options));
44 | //console.log("gauge1.options.units=" + gauge1.options.units);
45 | console.log("METER values[1]=" + values[1]);
46 | console.log("METER values[2]=" + values[2]);
47 | console.log("METER values[3]=" + values[3]);
48 | if (values[1] != "") {
49 | gauge1.options.units = values[1];
50 | document.getElementById("canvas1").style.display = "block";
51 | meter1 = 1;
52 | }
53 | if (values[2] != "") {
54 | gauge2.options.units = values[2];
55 | document.getElementById("canvas2").style.display = "block";
56 | meter2 = 1;
57 | }
58 | if (values[3] != "") {
59 | gauge3.options.units = values[3];
60 | document.getElementById("canvas3").style.display = "block";
61 | meter3 = 1;
62 | }
63 | break;
64 |
65 | case 'DATA':
66 | console.log("DATA values[1]=" + values[1]);
67 | var voltage1 = parseInt(values[1], 10);
68 | gauge1.value = voltage1;
69 | gauge1.update({ valueText: values[1] });
70 | if (meter2) {
71 | console.log("DATA values[2]=" + values[2]);
72 | var voltage2 = parseInt(values[2], 10);
73 | gauge2.value = voltage2;
74 | gauge2.update({ valueText: values[2] });
75 | }
76 | if (meter3) {
77 | console.log("DATA values[3]=" + values[3]);
78 | var voltage3 = parseInt(values[3], 10);
79 | gauge3.value = voltage3;
80 | gauge3.update({ valueText: values[3] });
81 | }
82 | break;
83 |
84 | default:
85 | break;
86 | }
87 | }
88 |
89 | websocket.onclose = function(evt) {
90 | console.log('Websocket connection closed');
91 | //document.getElementById("datetime").innerHTML = "WebSocket closed";
92 | }
93 |
94 | websocket.onerror = function(evt) {
95 | console.log('Websocket error: ' + evt);
96 | //document.getElementById("datetime").innerHTML = "WebSocket error????!!!1!!";
97 | }
98 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/html/root.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Canvas Gauge
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "main.c" "web_server.c" "web_client.c"
2 | INCLUDE_DIRS "."
3 | EMBED_FILES "../html/error.html"
4 | "../html/favicon.ico"
5 | "../html/main.js"
6 | "../html/root.html"
7 | "../html/main.css")
8 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "Application configuration"
2 |
3 | config GPIO_RANGE_MIN
4 | int
5 | default 32 if IDF_TARGET_ESP32
6 | default 1 if IDF_TARGET_ESP32S2
7 | default 1 if IDF_TARGET_ESP32S3
8 | default 0 if IDF_TARGET_ESP32C2
9 | default 0 if IDF_TARGET_ESP32C3
10 | default 0 if IDF_TARGET_ESP32C6
11 |
12 | config GPIO_RANGE_MAX
13 | int
14 | default 39 if IDF_TARGET_ESP32
15 | default 10 if IDF_TARGET_ESP32S2
16 | default 10 if IDF_TARGET_ESP32S3
17 | default 4 if IDF_TARGET_ESP32C2
18 | default 4 if IDF_TARGET_ESP32C3
19 | default 6 if IDF_TARGET_ESP32C6
20 |
21 | menu "WiFi Setting"
22 |
23 | config ESP_WIFI_SSID
24 | string "WiFi SSID"
25 | default "myssid"
26 | help
27 | SSID (network name) to connect to.
28 |
29 | config ESP_WIFI_PASSWORD
30 | string "WiFi Password"
31 | default "mypassword"
32 | help
33 | WiFi password (WPA or WPA2) to connect to.
34 |
35 | config ESP_MAXIMUM_RETRY
36 | int "Maximum retry"
37 | default 5
38 | help
39 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
40 |
41 | config MDNS_HOSTNAME
42 | string "mDNS Hostname"
43 | default "esp32-server"
44 | help
45 | The mDNS host name used by the ESP32.
46 |
47 | endmenu
48 |
49 | menu "ADC Setting"
50 |
51 | config METER1_GPIO
52 | int "GPIO for ADC1"
53 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
54 | default 32 if IDF_TARGET_ESP32
55 | default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
56 | default 0 # C3 and others
57 | help
58 | ADC1_CHANNEL number.
59 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
60 | On the ESP32, 8 channels: GPIO32 - GPIO39.
61 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
62 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
63 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
64 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
65 |
66 | config ENABLE_METER2
67 | bool "Enable METER2"
68 | default n
69 | help
70 | Enable Meter2.
71 |
72 | config METER2_GPIO
73 | depends on ENABLE_METER2
74 | int "GPIO for METER2"
75 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
76 | default 33 if IDF_TARGET_ESP32
77 | default 2 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
78 | default 1 # C3 and others
79 | help
80 | ADC1_CHANNEL number.
81 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
82 | On the ESP32, 8 channels: GPIO32 - GPIO39.
83 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
84 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
85 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
86 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
87 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
88 |
89 | config ENABLE_METER3
90 | bool "Enable METER3"
91 | default n
92 | help
93 | Enable Meter3.
94 |
95 | config METER3_GPIO
96 | depends on ENABLE_METER3
97 | int "GPIO for METER3"
98 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
99 | default 34 if IDF_TARGET_ESP32
100 | default 3 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
101 | default 2 # C3 and others
102 | help
103 | ADC1_CHANNEL number.
104 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
105 | On the ESP32, 8 channels: GPIO32 - GPIO39.
106 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
107 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
108 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
109 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
110 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
111 |
112 | config ADC_CYCLE
113 | int "ADC measurement cycle tick"
114 | range 100 1000
115 | default 100
116 | help
117 | ADC measurement cycle tick.
118 |
119 | config ENABLE_STDOUT
120 | bool "Enable STDOUT"
121 | default n
122 | help
123 | Enable STDOUT.
124 |
125 | endmenu
126 |
127 | endmenu
128 |
129 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/main/component.mk:
--------------------------------------------------------------------------------
1 | COMPONENT_EMBED_FILES := ../html/error.html
2 | COMPONENT_EMBED_FILES += ../html/favicon.ico
3 | COMPONENT_EMBED_FILES += ../html/main.js
4 | COMPONENT_EMBED_FILES += ../html/root.html
5 | COMPONENT_EMBED_FILES += ../html/bulma.css
6 | COMPONENT_EMBED_FILES += ../html/main.css
7 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/main/idf_component.yml:
--------------------------------------------------------------------------------
1 | ## IDF Component Manager Manifest File
2 | dependencies:
3 | Molorius/esp32-websocket:
4 | git: https://github.com/Molorius/esp32-websocket
5 | espressif/mdns:
6 | version: "^1.0.3"
7 | rules:
8 | - if: "idf_version >=5.0"
9 |
--------------------------------------------------------------------------------
/HorizontalLinearGauge/main/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/event_groups.h"
16 | #include "freertos/message_buffer.h"
17 |
18 | #include "esp_wifi.h"
19 | #include "esp_log.h"
20 | #include "nvs_flash.h"
21 | #include "mdns.h"
22 |
23 | #include "websocket_server.h"
24 |
25 | MessageBufferHandle_t xMessageBufferToClient;
26 |
27 | /* FreeRTOS event group to signal when we are connected*/
28 | static EventGroupHandle_t s_wifi_event_group;
29 |
30 | /* The event group allows multiple bits for each event, but we only care about two events:
31 | * - we are connected to the AP with an IP
32 | * - we failed to connect after the maximum amount of retries */
33 | #define WIFI_CONNECTED_BIT BIT0
34 | #define WIFI_FAIL_BIT BIT1
35 |
36 | static const char *TAG = "main";
37 |
38 | static int s_retry_num = 0;
39 |
40 | static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
41 | {
42 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
43 | esp_wifi_connect();
44 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
45 | if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
46 | esp_wifi_connect();
47 | s_retry_num++;
48 | ESP_LOGI(TAG, "retry to connect to the AP");
49 | } else {
50 | xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
51 | }
52 | ESP_LOGI(TAG,"connect to the AP fail");
53 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
54 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
55 | ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
56 | s_retry_num = 0;
57 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
58 | }
59 | }
60 |
61 | void wifi_init_sta(void)
62 | {
63 | s_wifi_event_group = xEventGroupCreate();
64 |
65 | ESP_ERROR_CHECK(esp_netif_init());
66 |
67 | ESP_ERROR_CHECK(esp_event_loop_create_default());
68 | esp_netif_create_default_wifi_sta();
69 |
70 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
71 | ESP_ERROR_CHECK(esp_wifi_init(&cfg));
72 |
73 | esp_event_handler_instance_t instance_any_id;
74 | esp_event_handler_instance_t instance_got_ip;
75 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
76 | ESP_EVENT_ANY_ID,
77 | &event_handler,
78 | NULL,
79 | &instance_any_id));
80 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
81 | IP_EVENT_STA_GOT_IP,
82 | &event_handler,
83 | NULL,
84 | &instance_got_ip));
85 |
86 | wifi_config_t wifi_config = {
87 | .sta = {
88 | .ssid = CONFIG_ESP_WIFI_SSID,
89 | .password = CONFIG_ESP_WIFI_PASSWORD,
90 | /* Setting a password implies station will connect to all security modes including WEP/WPA.
91 | * However these modes are deprecated and not advisable to be used. Incase your Access point
92 | * doesn't support WPA2, these mode can be enabled by commenting below line */
93 | .threshold.authmode = WIFI_AUTH_WPA2_PSK,
94 |
95 | .pmf_cfg = {
96 | .capable = true,
97 | .required = false
98 | },
99 | },
100 | };
101 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
102 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
103 | ESP_ERROR_CHECK(esp_wifi_start() );
104 |
105 | ESP_LOGI(TAG, "wifi_init_sta finished.");
106 |
107 | /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
108 | * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
109 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
110 | WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
111 | pdFALSE,
112 | pdFALSE,
113 | portMAX_DELAY);
114 |
115 | /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
116 | * happened. */
117 | if (bits & WIFI_CONNECTED_BIT) {
118 | ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
119 | } else if (bits & WIFI_FAIL_BIT) {
120 | ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
121 | } else {
122 | ESP_LOGE(TAG, "UNEXPECTED EVENT");
123 | }
124 |
125 | /* The event will not be processed after unregister */
126 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
127 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
128 | vEventGroupDelete(s_wifi_event_group);
129 | }
130 |
131 | void initialise_mdns(void)
132 | {
133 | //initialize mDNS
134 | ESP_ERROR_CHECK( mdns_init() );
135 | //set mDNS hostname (required if you want to advertise services)
136 | ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
137 | ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
138 |
139 | //initialize service
140 | ESP_ERROR_CHECK( mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) );
141 |
142 | #if 0
143 | //set default mDNS instance name
144 | ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
145 | #endif
146 | }
147 |
148 | void client_task(void* pvParameters);
149 | void server_task(void* pvParameters);
150 |
151 | void app_main() {
152 | // Initialize NVS
153 | esp_err_t ret = nvs_flash_init();
154 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
155 | ESP_ERROR_CHECK(nvs_flash_erase());
156 | ret = nvs_flash_init();
157 | }
158 | ESP_ERROR_CHECK(ret);
159 |
160 | // Initialize WiFi
161 | wifi_init_sta();
162 |
163 | // Initialize mDNS
164 | initialise_mdns();
165 |
166 | // Create Message Buffer
167 | xMessageBufferToClient = xMessageBufferCreate(1024);
168 | configASSERT( xMessageBufferToClient );
169 |
170 | // Get the local IP address
171 | esp_netif_ip_info_t ip_info;
172 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
173 | char cparam0[64];
174 | sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
175 |
176 | // Start web socket server
177 | ws_server_start();
178 |
179 | // Start web server
180 | xTaskCreate(&server_task, "server_task", 1024*4, (void *)cparam0, 5, NULL);
181 |
182 | // Start web client
183 | xTaskCreate(&client_task, "client_task", 1024*4, NULL, 5, NULL);
184 |
185 | vTaskDelay(100);
186 | }
187 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 nopnop2002
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PlotlyChart/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The following five lines of boilerplate have to be in your project's
2 | # CMakeLists in this exact order for cmake to work correctly
3 | cmake_minimum_required(VERSION 3.5)
4 |
5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6 | project(web-analog)
7 |
--------------------------------------------------------------------------------
/PlotlyChart/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 nopnop2002
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PlotlyChart/README.md:
--------------------------------------------------------------------------------
1 | # Chart display using plotly
2 | 
3 |
4 | I used [this](https://plotly.com/javascript/) for chart display.
5 | You can easily change the chart design.
6 |
7 |
--------------------------------------------------------------------------------
/PlotlyChart/html/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ESP32 Error 404
5 |
6 |
7 |
8 |
9 |
10 |
11 | Error 404
12 | Unknown page. Return home.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/PlotlyChart/html/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nopnop2002/esp-idf-web-chart/ce073d46522b28e6a06e84bd34ece938afb5857a/PlotlyChart/html/favicon.ico
--------------------------------------------------------------------------------
/PlotlyChart/html/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | Your favorite style is defined here.
3 | */
4 |
--------------------------------------------------------------------------------
/PlotlyChart/html/main.js:
--------------------------------------------------------------------------------
1 | //document.getElementById("datetime").innerHTML = "WebSocket is not connected";
2 |
3 | var websocket = new WebSocket('ws://'+location.hostname+'/');
4 | var meter1 = 0;
5 | var meter2 = 0;
6 | var meter3 = 0;
7 |
8 |
9 | function sendText(name) {
10 | console.log('sendText');
11 | var data = {};
12 | data["id"] = name;
13 | console.log('data=', data);
14 | json_data = JSON.stringify(data);
15 | console.log('json_data=' + json_data);
16 | websocket.send(json_data);
17 | }
18 |
19 | websocket.onopen = function(evt) {
20 | console.log('WebSocket connection opened');
21 | var data = {};
22 | data["id"] = "init";
23 | console.log('data=', data);
24 | json_data = JSON.stringify(data);
25 | console.log('json_data=' + json_data);
26 | websocket.send(json_data);
27 | //document.getElementById("datetime").innerHTML = "WebSocket is connected!";
28 | }
29 |
30 | websocket.onmessage = function(evt) {
31 | var msg = evt.data;
32 | console.log("msg=" + msg);
33 | var values = msg.split('\4'); // \4 is EOT
34 | //console.log("values=" + values);
35 | switch(values[0]) {
36 | case 'HEAD':
37 | console.log("HEAD values[1]=" + values[1]);
38 | var h1 = document.getElementById( 'header' );
39 | h1.textContent = values[1];
40 | break;
41 |
42 | case 'METER':
43 | //console.log("gauge1=" + Object.keys(gauge1.options));
44 | //console.log("gauge1.options.units=" + gauge1.options.units);
45 | console.log("METER values[1]=" + values[1]);
46 | console.log("METER values[2]=" + values[2]);
47 | console.log("METER values[3]=" + values[3]);
48 | if (values[1] != "") {
49 | Plotly.restyle('graph', 'visible', true, [0]);
50 | Plotly.restyle('graph', 'name', values[1], [0])
51 | meter1 = 1;
52 | }
53 | if (values[2] != "") {
54 | Plotly.restyle('graph', 'visible', true, [1]);
55 | Plotly.restyle('graph', 'name', values[2], [1])
56 | meter2 = 1;
57 | }
58 | if (values[3] != "") {
59 | Plotly.restyle('graph', 'visible', true, [2]);
60 | Plotly.restyle('graph', 'name', values[3], [2])
61 | meter3 = 1;
62 | }
63 | break;
64 |
65 | case 'DATA':
66 | console.log("DATA values[1]=" + values[1]);
67 | var voltage1 = parseInt(values[1], 10);
68 | var voltage2 = 0;
69 | var voltage3 = 0;
70 | if (meter2) {
71 | console.log("DATA values[2]=" + values[2]);
72 | voltage2 = parseInt(values[2], 10);
73 | }
74 | if (meter3) {
75 | console.log("DATA values[3]=" + values[3]);
76 | voltage3 = parseInt(values[3], 10);
77 | }
78 | var time = new Date();
79 | var update = {
80 | x: [[time], [time], [time]],
81 | y: [[voltage1], [voltage2], [voltage3]]
82 | }
83 |
84 | var olderTime = time.setMinutes(time.getMinutes() - 1);
85 | var futureTime = time.setMinutes(time.getMinutes() + 1);
86 |
87 | var minuteView = {
88 | xaxis: {
89 | type: 'date',
90 | range: [olderTime,futureTime]
91 | }
92 | };
93 |
94 | Plotly.relayout('graph', minuteView);
95 |
96 | Plotly.extendTraces('graph', update, [0, 1, 2])
97 | break;
98 |
99 | default:
100 | break;
101 | }
102 | }
103 |
104 | websocket.onclose = function(evt) {
105 | console.log('Websocket connection closed');
106 | //document.getElementById("datetime").innerHTML = "WebSocket closed";
107 | }
108 |
109 | websocket.onerror = function(evt) {
110 | console.log('Websocket error: ' + evt);
111 | //document.getElementById("datetime").innerHTML = "WebSocket error????!!!1!!";
112 | }
113 |
--------------------------------------------------------------------------------
/PlotlyChart/html/root.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Plotly Chart
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/PlotlyChart/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "main.c" "web_server.c" "web_client.c"
2 | INCLUDE_DIRS "."
3 | EMBED_FILES "../html/error.html"
4 | "../html/favicon.ico"
5 | "../html/main.js"
6 | "../html/root.html"
7 | "../html/main.css")
8 |
--------------------------------------------------------------------------------
/PlotlyChart/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "Application configuration"
2 |
3 | config GPIO_RANGE_MIN
4 | int
5 | default 32 if IDF_TARGET_ESP32
6 | default 1 if IDF_TARGET_ESP32S2
7 | default 1 if IDF_TARGET_ESP32S3
8 | default 0 if IDF_TARGET_ESP32C2
9 | default 0 if IDF_TARGET_ESP32C3
10 | default 0 if IDF_TARGET_ESP32C6
11 |
12 | config GPIO_RANGE_MAX
13 | int
14 | default 39 if IDF_TARGET_ESP32
15 | default 10 if IDF_TARGET_ESP32S2
16 | default 10 if IDF_TARGET_ESP32S3
17 | default 4 if IDF_TARGET_ESP32C2
18 | default 4 if IDF_TARGET_ESP32C3
19 | default 6 if IDF_TARGET_ESP32C6
20 |
21 | menu "WiFi Setting"
22 |
23 | config ESP_WIFI_SSID
24 | string "WiFi SSID"
25 | default "myssid"
26 | help
27 | SSID (network name) to connect to.
28 |
29 | config ESP_WIFI_PASSWORD
30 | string "WiFi Password"
31 | default "mypassword"
32 | help
33 | WiFi password (WPA or WPA2) to connect to.
34 |
35 | config ESP_MAXIMUM_RETRY
36 | int "Maximum retry"
37 | default 5
38 | help
39 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
40 |
41 | config MDNS_HOSTNAME
42 | string "mDNS Hostname"
43 | default "esp32-server"
44 | help
45 | The mDNS host name used by the ESP32.
46 |
47 | endmenu
48 |
49 | menu "ADC Setting"
50 |
51 | config METER1_GPIO
52 | int "GPIO for ADC1"
53 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
54 | default 32 if IDF_TARGET_ESP32
55 | default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
56 | default 0 # C3 and others
57 | help
58 | ADC1_CHANNEL number.
59 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
60 | On the ESP32, 8 channels: GPIO32 - GPIO39.
61 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
62 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
63 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
64 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
65 |
66 | config ENABLE_METER2
67 | bool "Enable METER2"
68 | default n
69 | help
70 | Enable Meter2.
71 |
72 | config METER2_GPIO
73 | depends on ENABLE_METER2
74 | int "GPIO for METER2"
75 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
76 | default 33 if IDF_TARGET_ESP32
77 | default 2 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
78 | default 1 # C3 and others
79 | help
80 | ADC1_CHANNEL number.
81 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
82 | On the ESP32, 8 channels: GPIO32 - GPIO39.
83 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
84 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
85 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
86 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
87 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
88 |
89 | config ENABLE_METER3
90 | bool "Enable METER3"
91 | default n
92 | help
93 | Enable Meter3.
94 |
95 | config METER3_GPIO
96 | depends on ENABLE_METER3
97 | int "GPIO for METER3"
98 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
99 | default 34 if IDF_TARGET_ESP32
100 | default 3 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
101 | default 2 # C3 and others
102 | help
103 | ADC1_CHANNEL number.
104 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
105 | On the ESP32, 8 channels: GPIO32 - GPIO39.
106 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
107 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
108 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
109 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
110 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
111 |
112 | config ADC_CYCLE
113 | int "ADC measurement cycle tick"
114 | range 100 1000
115 | default 100
116 | help
117 | ADC measurement cycle tick.
118 |
119 | config ENABLE_STDOUT
120 | bool "Enable STDOUT"
121 | default n
122 | help
123 | Enable STDOUT.
124 |
125 | endmenu
126 |
127 | endmenu
128 |
129 |
--------------------------------------------------------------------------------
/PlotlyChart/main/component.mk:
--------------------------------------------------------------------------------
1 | COMPONENT_EMBED_FILES := ../html/error.html
2 | COMPONENT_EMBED_FILES += ../html/favicon.ico
3 | COMPONENT_EMBED_FILES += ../html/main.js
4 | COMPONENT_EMBED_FILES += ../html/root.html
5 | COMPONENT_EMBED_FILES += ../html/bulma.css
6 | COMPONENT_EMBED_FILES += ../html/main.css
7 |
--------------------------------------------------------------------------------
/PlotlyChart/main/idf_component.yml:
--------------------------------------------------------------------------------
1 | ## IDF Component Manager Manifest File
2 | dependencies:
3 | Molorius/esp32-websocket:
4 | git: https://github.com/Molorius/esp32-websocket
5 | espressif/mdns:
6 | version: "^1.0.3"
7 | rules:
8 | - if: "idf_version >=5.0"
9 |
--------------------------------------------------------------------------------
/PlotlyChart/main/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/event_groups.h"
16 | #include "freertos/message_buffer.h"
17 |
18 | #include "esp_wifi.h"
19 | #include "esp_log.h"
20 | #include "nvs_flash.h"
21 | #include "mdns.h"
22 |
23 | #include "websocket_server.h"
24 |
25 | MessageBufferHandle_t xMessageBufferToClient;
26 |
27 | /* FreeRTOS event group to signal when we are connected*/
28 | static EventGroupHandle_t s_wifi_event_group;
29 |
30 | /* The event group allows multiple bits for each event, but we only care about two events:
31 | * - we are connected to the AP with an IP
32 | * - we failed to connect after the maximum amount of retries */
33 | #define WIFI_CONNECTED_BIT BIT0
34 | #define WIFI_FAIL_BIT BIT1
35 |
36 | static const char *TAG = "main";
37 |
38 | static int s_retry_num = 0;
39 |
40 | static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
41 | {
42 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
43 | esp_wifi_connect();
44 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
45 | if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
46 | esp_wifi_connect();
47 | s_retry_num++;
48 | ESP_LOGI(TAG, "retry to connect to the AP");
49 | } else {
50 | xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
51 | }
52 | ESP_LOGI(TAG,"connect to the AP fail");
53 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
54 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
55 | ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
56 | s_retry_num = 0;
57 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
58 | }
59 | }
60 |
61 | void wifi_init_sta(void)
62 | {
63 | s_wifi_event_group = xEventGroupCreate();
64 |
65 | ESP_ERROR_CHECK(esp_netif_init());
66 |
67 | ESP_ERROR_CHECK(esp_event_loop_create_default());
68 | esp_netif_create_default_wifi_sta();
69 |
70 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
71 | ESP_ERROR_CHECK(esp_wifi_init(&cfg));
72 |
73 | esp_event_handler_instance_t instance_any_id;
74 | esp_event_handler_instance_t instance_got_ip;
75 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
76 | ESP_EVENT_ANY_ID,
77 | &event_handler,
78 | NULL,
79 | &instance_any_id));
80 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
81 | IP_EVENT_STA_GOT_IP,
82 | &event_handler,
83 | NULL,
84 | &instance_got_ip));
85 |
86 | wifi_config_t wifi_config = {
87 | .sta = {
88 | .ssid = CONFIG_ESP_WIFI_SSID,
89 | .password = CONFIG_ESP_WIFI_PASSWORD,
90 | /* Setting a password implies station will connect to all security modes including WEP/WPA.
91 | * However these modes are deprecated and not advisable to be used. Incase your Access point
92 | * doesn't support WPA2, these mode can be enabled by commenting below line */
93 | .threshold.authmode = WIFI_AUTH_WPA2_PSK,
94 |
95 | .pmf_cfg = {
96 | .capable = true,
97 | .required = false
98 | },
99 | },
100 | };
101 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
102 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
103 | ESP_ERROR_CHECK(esp_wifi_start() );
104 |
105 | ESP_LOGI(TAG, "wifi_init_sta finished.");
106 |
107 | /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
108 | * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
109 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
110 | WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
111 | pdFALSE,
112 | pdFALSE,
113 | portMAX_DELAY);
114 |
115 | /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
116 | * happened. */
117 | if (bits & WIFI_CONNECTED_BIT) {
118 | ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
119 | } else if (bits & WIFI_FAIL_BIT) {
120 | ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
121 | } else {
122 | ESP_LOGE(TAG, "UNEXPECTED EVENT");
123 | }
124 |
125 | /* The event will not be processed after unregister */
126 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
127 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
128 | vEventGroupDelete(s_wifi_event_group);
129 | }
130 |
131 | void initialise_mdns(void)
132 | {
133 | //initialize mDNS
134 | ESP_ERROR_CHECK( mdns_init() );
135 | //set mDNS hostname (required if you want to advertise services)
136 | ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
137 | ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
138 |
139 | //initialize service
140 | ESP_ERROR_CHECK( mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) );
141 |
142 | #if 0
143 | //set default mDNS instance name
144 | ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
145 | #endif
146 | }
147 |
148 | void client_task(void* pvParameters);
149 | void server_task(void* pvParameters);
150 |
151 | void app_main() {
152 | // Initialize NVS
153 | esp_err_t ret = nvs_flash_init();
154 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
155 | ESP_ERROR_CHECK(nvs_flash_erase());
156 | ret = nvs_flash_init();
157 | }
158 | ESP_ERROR_CHECK(ret);
159 |
160 | // Initialize WiFi
161 | wifi_init_sta();
162 |
163 | // Initialize mDNS
164 | initialise_mdns();
165 |
166 | // Create Message Buffer
167 | xMessageBufferToClient = xMessageBufferCreate(1024);
168 | configASSERT( xMessageBufferToClient );
169 |
170 | // Get the local IP address
171 | esp_netif_ip_info_t ip_info;
172 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
173 | char cparam0[64];
174 | sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
175 |
176 | // Start web socket server
177 | ws_server_start();
178 |
179 | // Start web server
180 | xTaskCreate(&server_task, "server_task", 1024*4, (void *)cparam0, 5, NULL);
181 |
182 | // Start web client
183 | xTaskCreate(&client_task, "client_task", 1024*4, NULL, 5, NULL);
184 |
185 | vTaskDelay(100);
186 | }
187 |
--------------------------------------------------------------------------------
/PlotlyChart/main/web_server.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/message_buffer.h"
16 | #include "esp_log.h"
17 |
18 | #include "websocket_server.h"
19 |
20 | static QueueHandle_t client_queue;
21 | extern MessageBufferHandle_t xMessageBufferToClient;
22 |
23 | const static int client_queue_size = 10;
24 |
25 | // handles websocket events
26 | void websocket_callback(uint8_t num,WEBSOCKET_TYPE_t type,char* msg,uint64_t len) {
27 | const static char* TAG = "websocket_callback";
28 | //int value;
29 |
30 | switch(type) {
31 | case WEBSOCKET_CONNECT:
32 | ESP_LOGI(TAG,"client %i connected!",num);
33 | break;
34 | case WEBSOCKET_DISCONNECT_EXTERNAL:
35 | ESP_LOGI(TAG,"client %i sent a disconnect message",num);
36 | break;
37 | case WEBSOCKET_DISCONNECT_INTERNAL:
38 | ESP_LOGI(TAG,"client %i was disconnected",num);
39 | break;
40 | case WEBSOCKET_DISCONNECT_ERROR:
41 | ESP_LOGI(TAG,"client %i was disconnected due to an error",num);
42 | break;
43 | case WEBSOCKET_TEXT:
44 | if(len) { // if the message length was greater than zero
45 | ESP_LOGI(TAG, "got message length %i: %s", (int)len, msg);
46 | size_t xBytesSent = xMessageBufferSendFromISR(xMessageBufferToClient, msg, len, NULL);
47 | if (xBytesSent != len) {
48 | ESP_LOGE(TAG, "xMessageBufferSend fail");
49 | }
50 | }
51 | break;
52 | case WEBSOCKET_BIN:
53 | ESP_LOGI(TAG,"client %i sent binary message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
54 | break;
55 | case WEBSOCKET_PING:
56 | ESP_LOGI(TAG,"client %i pinged us with message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
57 | break;
58 | case WEBSOCKET_PONG:
59 | ESP_LOGI(TAG,"client %i responded to the ping",num);
60 | break;
61 | }
62 | }
63 |
64 | // serves any clients
65 | static void http_server(struct netconn *conn) {
66 | const static char* TAG = "http_server";
67 | const static char HTML_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/html\n\n";
68 | const static char ERROR_HEADER[] = "HTTP/1.1 404 Not Found\nContent-type: text/html\n\n";
69 | const static char JS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\n\n";
70 | const static char CSS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/css\n\n";
71 | //const static char PNG_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/png\n\n";
72 | const static char ICO_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/x-icon\n\n";
73 | //const static char PDF_HEADER[] = "HTTP/1.1 200 OK\nContent-type: application/pdf\n\n";
74 | //const static char EVENT_HEADER[] = "HTTP/1.1 200 OK\nContent-Type: text/event-stream\nCache-Control: no-cache\nretry: 3000\n\n";
75 | struct netbuf* inbuf;
76 | static char* buf;
77 | static uint16_t buflen;
78 | static err_t err;
79 |
80 | // default page
81 | extern const uint8_t root_html_start[] asm("_binary_root_html_start");
82 | extern const uint8_t root_html_end[] asm("_binary_root_html_end");
83 | const uint32_t root_html_len = root_html_end - root_html_start;
84 |
85 | // main.js
86 | extern const uint8_t main_js_start[] asm("_binary_main_js_start");
87 | extern const uint8_t main_js_end[] asm("_binary_main_js_end");
88 | const uint32_t main_js_len = main_js_end - main_js_start;
89 |
90 | // main.css
91 | extern const uint8_t main_css_start[] asm("_binary_main_css_start");
92 | extern const uint8_t main_css_end[] asm("_binary_main_css_end");
93 | const uint32_t main_css_len = main_css_end - main_css_start;
94 |
95 | // favicon.ico
96 | extern const uint8_t favicon_ico_start[] asm("_binary_favicon_ico_start");
97 | extern const uint8_t favicon_ico_end[] asm("_binary_favicon_ico_end");
98 | const uint32_t favicon_ico_len = favicon_ico_end - favicon_ico_start;
99 |
100 | // error page
101 | extern const uint8_t error_html_start[] asm("_binary_error_html_start");
102 | extern const uint8_t error_html_end[] asm("_binary_error_html_end");
103 | const uint32_t error_html_len = error_html_end - error_html_start;
104 |
105 | netconn_set_recvtimeout(conn,1000); // allow a connection timeout of 1 second
106 | ESP_LOGI(TAG,"reading from client...");
107 | err = netconn_recv(conn, &inbuf);
108 | ESP_LOGI(TAG,"read from client");
109 | if(err==ERR_OK) {
110 | netbuf_data(inbuf, (void**)&buf, &buflen);
111 | if(buf) {
112 |
113 | ESP_LOGD(TAG, "buf=[%s]", buf);
114 | // default page
115 | if (strstr(buf,"GET / ")
116 | && !strstr(buf,"Upgrade: websocket")) {
117 | ESP_LOGI(TAG,"Sending /");
118 | netconn_write(conn, HTML_HEADER, sizeof(HTML_HEADER)-1,NETCONN_NOCOPY);
119 | netconn_write(conn, root_html_start,root_html_len,NETCONN_NOCOPY);
120 | netconn_close(conn);
121 | netconn_delete(conn);
122 | netbuf_delete(inbuf);
123 | }
124 |
125 | // default page websocket
126 | else if(strstr(buf,"GET / ")
127 | && strstr(buf,"Upgrade: websocket")) {
128 | ESP_LOGI(TAG,"Requesting websocket on /");
129 | ws_server_add_client(conn,buf,buflen,"/",websocket_callback);
130 | netbuf_delete(inbuf);
131 | }
132 |
133 | else if(strstr(buf,"GET /main.js ")) {
134 | ESP_LOGI(TAG,"Sending /main.js");
135 | netconn_write(conn, JS_HEADER, sizeof(JS_HEADER)-1,NETCONN_NOCOPY);
136 | netconn_write(conn, main_js_start, main_js_len,NETCONN_NOCOPY);
137 | netconn_close(conn);
138 | netconn_delete(conn);
139 | netbuf_delete(inbuf);
140 | }
141 |
142 | else if(strstr(buf,"GET /main.css ")) {
143 | ESP_LOGI(TAG,"Sending /main.css");
144 | netconn_write(conn, CSS_HEADER, sizeof(CSS_HEADER)-1,NETCONN_NOCOPY);
145 | netconn_write(conn, main_css_start, main_css_len,NETCONN_NOCOPY);
146 | netconn_close(conn);
147 | netconn_delete(conn);
148 | netbuf_delete(inbuf);
149 | }
150 |
151 | else if(strstr(buf,"GET /favicon.ico ")) {
152 | ESP_LOGI(TAG,"Sending favicon.ico");
153 | netconn_write(conn,ICO_HEADER,sizeof(ICO_HEADER)-1,NETCONN_NOCOPY);
154 | netconn_write(conn,favicon_ico_start,favicon_ico_len,NETCONN_NOCOPY);
155 | netconn_close(conn);
156 | netconn_delete(conn);
157 | netbuf_delete(inbuf);
158 | }
159 |
160 | else if(strstr(buf,"GET /")) {
161 | ESP_LOGE(TAG,"Unknown request, sending error page: %s",buf);
162 | netconn_write(conn, ERROR_HEADER, sizeof(ERROR_HEADER)-1,NETCONN_NOCOPY);
163 | netconn_write(conn, error_html_start, error_html_len,NETCONN_NOCOPY);
164 | netconn_close(conn);
165 | netconn_delete(conn);
166 | netbuf_delete(inbuf);
167 | }
168 |
169 | else {
170 | ESP_LOGE(TAG,"Unknown request");
171 | netconn_close(conn);
172 | netconn_delete(conn);
173 | netbuf_delete(inbuf);
174 | }
175 | }
176 | else {
177 | ESP_LOGI(TAG,"Unknown request (empty?...)");
178 | netconn_close(conn);
179 | netconn_delete(conn);
180 | netbuf_delete(inbuf);
181 | }
182 | }
183 | else { // if err==ERR_OK
184 | ESP_LOGI(TAG,"error on read, closing connection");
185 | netconn_close(conn);
186 | netconn_delete(conn);
187 | netbuf_delete(inbuf);
188 | }
189 | }
190 |
191 | // receives clients from queue, handles them
192 | void server_handle_task(void* pvParameters) {
193 | const static char* TAG = "server_handle_task";
194 | struct netconn* conn;
195 | ESP_LOGI(TAG,"task starting");
196 | for(;;) {
197 | xQueueReceive(client_queue,&conn,portMAX_DELAY);
198 | if(!conn) continue;
199 | http_server(conn);
200 | }
201 | vTaskDelete(NULL);
202 | }
203 |
204 | // handles clients when they first connect. passes to a queue
205 | void server_task(void* pvParameters) {
206 | const static char* TAG = "server_task";
207 | char *task_parameter = (char *)pvParameters;
208 | ESP_LOGI(TAG, "Start task_parameter=%s", task_parameter);
209 | char url[64];
210 | sprintf(url, "http://%s", task_parameter);
211 | ESP_LOGI(TAG, "Starting server on %s", url);
212 |
213 | struct netconn *conn, *newconn;
214 | static err_t err;
215 | client_queue = xQueueCreate(client_queue_size,sizeof(struct netconn*));
216 | configASSERT( client_queue );
217 |
218 |
219 | UBaseType_t PriorityGet = uxTaskPriorityGet(NULL);
220 | ESP_LOGI(TAG, "PriorityGet=%d", PriorityGet);
221 | xTaskCreate(&server_handle_task, "server_handle_task", 1024*3, NULL, PriorityGet, NULL);
222 |
223 |
224 | conn = netconn_new(NETCONN_TCP);
225 | netconn_bind(conn,NULL,80);
226 | netconn_listen(conn);
227 | ESP_LOGI(TAG,"server listening");
228 | do {
229 | err = netconn_accept(conn, &newconn);
230 | ESP_LOGI(TAG,"new client");
231 | if(err == ERR_OK) {
232 | xQueueSendToBack(client_queue,&newconn,portMAX_DELAY);
233 | //http_server(newconn);
234 | }
235 | } while(err == ERR_OK);
236 | netconn_close(conn);
237 | netconn_delete(conn);
238 | ESP_LOGE(TAG,"task ending, rebooting board");
239 | esp_restart();
240 | }
241 |
--------------------------------------------------------------------------------
/PlotlyGauge/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The following five lines of boilerplate have to be in your project's
2 | # CMakeLists in this exact order for cmake to work correctly
3 | cmake_minimum_required(VERSION 3.5)
4 |
5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6 | project(web-analog)
7 |
--------------------------------------------------------------------------------
/PlotlyGauge/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 nopnop2002
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PlotlyGauge/README.md:
--------------------------------------------------------------------------------
1 | # Gauge display using plotly
2 | 
3 |
4 | I used [this](https://plotly.com/javascript/) for gauge display.
5 | You can easily change the chart design.
6 |
7 |
--------------------------------------------------------------------------------
/PlotlyGauge/html/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ESP32 Error 404
5 |
6 |
7 |
8 |
9 |
10 |
11 | Error 404
12 | Unknown page. Return home.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/PlotlyGauge/html/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nopnop2002/esp-idf-web-chart/ce073d46522b28e6a06e84bd34ece938afb5857a/PlotlyGauge/html/favicon.ico
--------------------------------------------------------------------------------
/PlotlyGauge/html/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | Your favorite style is defined here.
3 | */
4 |
--------------------------------------------------------------------------------
/PlotlyGauge/html/main.js:
--------------------------------------------------------------------------------
1 | //document.getElementById("datetime").innerHTML = "WebSocket is not connected";
2 |
3 | var websocket = new WebSocket('ws://'+location.hostname+'/');
4 |
5 | var data1 = [
6 | {
7 | domain: { x: [0, 1], y: [0, 1] },
8 | title: { text: "" },
9 | value: 0,
10 | type: "indicator",
11 | mode: "gauge+number",
12 | gauge: {
13 | axis: { range: [null, 3000] },
14 | steps: [
15 | { range: [0, 2000], color: "cyan" },
16 | { range: [2000, 3000], color: "royalblue" }
17 | ],
18 | }
19 | }
20 | ];
21 |
22 | var data2 = data1;
23 | var data3 = data1;
24 |
25 | var layout = { width: 400, height: 300, margin: { t: 0, b: 0 } };
26 |
27 | Plotly.newPlot('gauge1', data1, layout);
28 | Plotly.newPlot('gauge2', data2, layout);
29 | Plotly.newPlot('gauge3', data3, layout);
30 |
31 | var meter1 = 0;
32 | var meter2 = 0;
33 | var meter3 = 0;
34 | var gpio1 = "";
35 | var gpio2 = "";
36 | var gpio3 = "";
37 |
38 |
39 | function sendText(name) {
40 | console.log('sendText');
41 | var data = {};
42 | data["id"] = name;
43 | console.log('data=', data);
44 | json_data = JSON.stringify(data);
45 | console.log('json_data=' + json_data);
46 | websocket.send(json_data);
47 | }
48 |
49 | websocket.onopen = function(evt) {
50 | console.log('WebSocket connection opened');
51 | var data = {};
52 | data["id"] = "init";
53 | console.log('data=', data);
54 | json_data = JSON.stringify(data);
55 | console.log('json_data=' + json_data);
56 | websocket.send(json_data);
57 | //document.getElementById("datetime").innerHTML = "WebSocket is connected!";
58 | }
59 |
60 | websocket.onmessage = function(evt) {
61 | var msg = evt.data;
62 | console.log("msg=" + msg);
63 | var values = msg.split('\4'); // \4 is EOT
64 | //console.log("values=" + values);
65 | switch(values[0]) {
66 | case 'HEAD':
67 | console.log("HEAD values[1]=" + values[1]);
68 | var h1 = document.getElementById( 'header' );
69 | h1.textContent = values[1];
70 | break;
71 |
72 | case 'METER':
73 | //console.log("gauge1=" + Object.keys(gauge1.options));
74 | //console.log("gauge1.options.units=" + gauge1.options.units);
75 | console.log("METER values[1]=" + values[1]);
76 | console.log("METER values[2]=" + values[2]);
77 | console.log("METER values[3]=" + values[3]);
78 | if (values[1] != "") {
79 | meter1 = 1;
80 | gpio1 = values[1];
81 | document.getElementById("gauge1").style.display = "inline-block";
82 | }
83 | if (values[2] != "") {
84 | meter2 = 1;
85 | gpio2 = values[2];
86 | document.getElementById("gauge2").style.display = "inline-block";
87 | }
88 | if (values[3] != "") {
89 | meter3 = 1;
90 | gpio3 = values[3];
91 | document.getElementById("gauge3").style.display = "inline-block";
92 | }
93 | break;
94 |
95 | case 'DATA':
96 | console.log("DATA values[1]=" + values[1]);
97 | var voltage1 = parseInt(values[1], 10);
98 | var data1_update = {
99 | title: { text: gpio1 },
100 | value: voltage1,
101 | };
102 | Plotly.update('gauge1', data1_update, layout)
103 |
104 | var voltage2 = 0;
105 | var voltage3 = 0;
106 | if (meter2) {
107 | console.log("DATA values[2]=" + values[2]);
108 | voltage2 = parseInt(values[2], 10);
109 | var data2_update = {
110 | title: { text: gpio2 },
111 | value: voltage2,
112 | };
113 | Plotly.update('gauge2', data2_update, layout)
114 | }
115 | if (meter3) {
116 | console.log("DATA values[3]=" + values[3]);
117 | voltage3 = parseInt(values[3], 10);
118 | var data3_update = {
119 | title: { text: gpio3 },
120 | value: voltage3,
121 | };
122 | Plotly.update('gauge3', data3_update, layout)
123 | }
124 | break;
125 |
126 | default:
127 | break;
128 | }
129 | }
130 |
131 | websocket.onclose = function(evt) {
132 | console.log('Websocket connection closed');
133 | //document.getElementById("datetime").innerHTML = "WebSocket closed";
134 | }
135 |
136 | websocket.onerror = function(evt) {
137 | console.log('Websocket error: ' + evt);
138 | //document.getElementById("datetime").innerHTML = "WebSocket error????!!!1!!";
139 | }
140 |
--------------------------------------------------------------------------------
/PlotlyGauge/html/root.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 | Plotly Gauge
13 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/PlotlyGauge/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "main.c" "web_server.c" "web_client.c"
2 | INCLUDE_DIRS "."
3 | EMBED_FILES "../html/error.html"
4 | "../html/favicon.ico"
5 | "../html/main.js"
6 | "../html/root.html"
7 | "../html/main.css")
8 |
--------------------------------------------------------------------------------
/PlotlyGauge/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "Application configuration"
2 |
3 | config GPIO_RANGE_MIN
4 | int
5 | default 32 if IDF_TARGET_ESP32
6 | default 1 if IDF_TARGET_ESP32S2
7 | default 1 if IDF_TARGET_ESP32S3
8 | default 0 if IDF_TARGET_ESP32C2
9 | default 0 if IDF_TARGET_ESP32C3
10 | default 0 if IDF_TARGET_ESP32C6
11 |
12 | config GPIO_RANGE_MAX
13 | int
14 | default 39 if IDF_TARGET_ESP32
15 | default 10 if IDF_TARGET_ESP32S2
16 | default 10 if IDF_TARGET_ESP32S3
17 | default 4 if IDF_TARGET_ESP32C2
18 | default 4 if IDF_TARGET_ESP32C3
19 | default 6 if IDF_TARGET_ESP32C6
20 |
21 | menu "WiFi Setting"
22 |
23 | config ESP_WIFI_SSID
24 | string "WiFi SSID"
25 | default "myssid"
26 | help
27 | SSID (network name) to connect to.
28 |
29 | config ESP_WIFI_PASSWORD
30 | string "WiFi Password"
31 | default "mypassword"
32 | help
33 | WiFi password (WPA or WPA2) to connect to.
34 |
35 | config ESP_MAXIMUM_RETRY
36 | int "Maximum retry"
37 | default 5
38 | help
39 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
40 |
41 | config MDNS_HOSTNAME
42 | string "mDNS Hostname"
43 | default "esp32-server"
44 | help
45 | The mDNS host name used by the ESP32.
46 |
47 | endmenu
48 |
49 | menu "ADC Setting"
50 |
51 | config METER1_GPIO
52 | int "GPIO for ADC1"
53 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
54 | default 32 if IDF_TARGET_ESP32
55 | default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
56 | default 0 # C3 and others
57 | help
58 | ADC1_CHANNEL number.
59 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
60 | On the ESP32, 8 channels: GPIO32 - GPIO39.
61 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
62 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
63 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
64 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
65 |
66 | config ENABLE_METER2
67 | bool "Enable METER2"
68 | default n
69 | help
70 | Enable Meter2.
71 |
72 | config METER2_GPIO
73 | depends on ENABLE_METER2
74 | int "GPIO for METER2"
75 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
76 | default 33 if IDF_TARGET_ESP32
77 | default 2 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
78 | default 1 # C3 and others
79 | help
80 | ADC1_CHANNEL number.
81 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
82 | On the ESP32, 8 channels: GPIO32 - GPIO39.
83 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
84 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
85 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
86 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
87 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
88 |
89 | config ENABLE_METER3
90 | bool "Enable METER3"
91 | default n
92 | help
93 | Enable Meter3.
94 |
95 | config METER3_GPIO
96 | depends on ENABLE_METER3
97 | int "GPIO for METER3"
98 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
99 | default 34 if IDF_TARGET_ESP32
100 | default 3 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
101 | default 2 # C3 and others
102 | help
103 | ADC1_CHANNEL number.
104 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
105 | On the ESP32, 8 channels: GPIO32 - GPIO39.
106 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
107 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
108 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
109 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
110 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
111 |
112 | config ADC_CYCLE
113 | int "ADC measurement cycle tick"
114 | range 100 1000
115 | default 100
116 | help
117 | ADC measurement cycle tick.
118 |
119 | config ENABLE_STDOUT
120 | bool "Enable STDOUT"
121 | default n
122 | help
123 | Enable STDOUT.
124 |
125 | endmenu
126 |
127 | endmenu
128 |
129 |
--------------------------------------------------------------------------------
/PlotlyGauge/main/component.mk:
--------------------------------------------------------------------------------
1 | COMPONENT_EMBED_FILES := ../html/error.html
2 | COMPONENT_EMBED_FILES += ../html/favicon.ico
3 | COMPONENT_EMBED_FILES += ../html/main.js
4 | COMPONENT_EMBED_FILES += ../html/root.html
5 | COMPONENT_EMBED_FILES += ../html/bulma.css
6 | COMPONENT_EMBED_FILES += ../html/main.css
7 |
--------------------------------------------------------------------------------
/PlotlyGauge/main/idf_component.yml:
--------------------------------------------------------------------------------
1 | ## IDF Component Manager Manifest File
2 | dependencies:
3 | Molorius/esp32-websocket:
4 | git: https://github.com/Molorius/esp32-websocket
5 | espressif/mdns:
6 | version: "^1.0.3"
7 | rules:
8 | - if: "idf_version >=5.0"
9 |
--------------------------------------------------------------------------------
/PlotlyGauge/main/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/event_groups.h"
16 | #include "freertos/message_buffer.h"
17 |
18 | #include "esp_wifi.h"
19 | #include "esp_log.h"
20 | #include "nvs_flash.h"
21 | #include "mdns.h"
22 |
23 | #include "websocket_server.h"
24 |
25 | MessageBufferHandle_t xMessageBufferToClient;
26 |
27 | /* FreeRTOS event group to signal when we are connected*/
28 | static EventGroupHandle_t s_wifi_event_group;
29 |
30 | /* The event group allows multiple bits for each event, but we only care about two events:
31 | * - we are connected to the AP with an IP
32 | * - we failed to connect after the maximum amount of retries */
33 | #define WIFI_CONNECTED_BIT BIT0
34 | #define WIFI_FAIL_BIT BIT1
35 |
36 | static const char *TAG = "main";
37 |
38 | static int s_retry_num = 0;
39 |
40 | static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
41 | {
42 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
43 | esp_wifi_connect();
44 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
45 | if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
46 | esp_wifi_connect();
47 | s_retry_num++;
48 | ESP_LOGI(TAG, "retry to connect to the AP");
49 | } else {
50 | xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
51 | }
52 | ESP_LOGI(TAG,"connect to the AP fail");
53 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
54 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
55 | ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
56 | s_retry_num = 0;
57 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
58 | }
59 | }
60 |
61 | void wifi_init_sta(void)
62 | {
63 | s_wifi_event_group = xEventGroupCreate();
64 |
65 | ESP_ERROR_CHECK(esp_netif_init());
66 |
67 | ESP_ERROR_CHECK(esp_event_loop_create_default());
68 | esp_netif_create_default_wifi_sta();
69 |
70 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
71 | ESP_ERROR_CHECK(esp_wifi_init(&cfg));
72 |
73 | esp_event_handler_instance_t instance_any_id;
74 | esp_event_handler_instance_t instance_got_ip;
75 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
76 | ESP_EVENT_ANY_ID,
77 | &event_handler,
78 | NULL,
79 | &instance_any_id));
80 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
81 | IP_EVENT_STA_GOT_IP,
82 | &event_handler,
83 | NULL,
84 | &instance_got_ip));
85 |
86 | wifi_config_t wifi_config = {
87 | .sta = {
88 | .ssid = CONFIG_ESP_WIFI_SSID,
89 | .password = CONFIG_ESP_WIFI_PASSWORD,
90 | /* Setting a password implies station will connect to all security modes including WEP/WPA.
91 | * However these modes are deprecated and not advisable to be used. Incase your Access point
92 | * doesn't support WPA2, these mode can be enabled by commenting below line */
93 | .threshold.authmode = WIFI_AUTH_WPA2_PSK,
94 |
95 | .pmf_cfg = {
96 | .capable = true,
97 | .required = false
98 | },
99 | },
100 | };
101 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
102 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
103 | ESP_ERROR_CHECK(esp_wifi_start() );
104 |
105 | ESP_LOGI(TAG, "wifi_init_sta finished.");
106 |
107 | /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
108 | * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
109 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
110 | WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
111 | pdFALSE,
112 | pdFALSE,
113 | portMAX_DELAY);
114 |
115 | /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
116 | * happened. */
117 | if (bits & WIFI_CONNECTED_BIT) {
118 | ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
119 | } else if (bits & WIFI_FAIL_BIT) {
120 | ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
121 | } else {
122 | ESP_LOGE(TAG, "UNEXPECTED EVENT");
123 | }
124 |
125 | /* The event will not be processed after unregister */
126 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
127 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
128 | vEventGroupDelete(s_wifi_event_group);
129 | }
130 |
131 | void initialise_mdns(void)
132 | {
133 | //initialize mDNS
134 | ESP_ERROR_CHECK( mdns_init() );
135 | //set mDNS hostname (required if you want to advertise services)
136 | ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
137 | ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
138 |
139 | //initialize service
140 | ESP_ERROR_CHECK( mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) );
141 |
142 | #if 0
143 | //set default mDNS instance name
144 | ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
145 | #endif
146 | }
147 |
148 | void client_task(void* pvParameters);
149 | void server_task(void* pvParameters);
150 |
151 | void app_main() {
152 | // Initialize NVS
153 | esp_err_t ret = nvs_flash_init();
154 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
155 | ESP_ERROR_CHECK(nvs_flash_erase());
156 | ret = nvs_flash_init();
157 | }
158 | ESP_ERROR_CHECK(ret);
159 |
160 | // Initialize WiFi
161 | wifi_init_sta();
162 |
163 | // Initialize mDNS
164 | initialise_mdns();
165 |
166 | // Create Message Buffer
167 | xMessageBufferToClient = xMessageBufferCreate(1024);
168 | configASSERT( xMessageBufferToClient );
169 |
170 | // Get the local IP address
171 | esp_netif_ip_info_t ip_info;
172 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
173 | char cparam0[64];
174 | sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
175 |
176 | // Start web socket server
177 | ws_server_start();
178 |
179 | // Start web server
180 | xTaskCreate(&server_task, "server_task", 1024*4, (void *)cparam0, 5, NULL);
181 |
182 | // Start web client
183 | xTaskCreate(&client_task, "client_task", 1024*4, NULL, 5, NULL);
184 |
185 | vTaskDelay(100);
186 | }
187 |
--------------------------------------------------------------------------------
/PlotlyGauge/main/web_server.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/message_buffer.h"
16 | #include "esp_log.h"
17 |
18 | #include "websocket_server.h"
19 |
20 | static QueueHandle_t client_queue;
21 | extern MessageBufferHandle_t xMessageBufferToClient;
22 |
23 | const static int client_queue_size = 10;
24 |
25 | // handles websocket events
26 | void websocket_callback(uint8_t num,WEBSOCKET_TYPE_t type,char* msg,uint64_t len) {
27 | const static char* TAG = "websocket_callback";
28 | //int value;
29 |
30 | switch(type) {
31 | case WEBSOCKET_CONNECT:
32 | ESP_LOGI(TAG,"client %i connected!",num);
33 | break;
34 | case WEBSOCKET_DISCONNECT_EXTERNAL:
35 | ESP_LOGI(TAG,"client %i sent a disconnect message",num);
36 | break;
37 | case WEBSOCKET_DISCONNECT_INTERNAL:
38 | ESP_LOGI(TAG,"client %i was disconnected",num);
39 | break;
40 | case WEBSOCKET_DISCONNECT_ERROR:
41 | ESP_LOGI(TAG,"client %i was disconnected due to an error",num);
42 | break;
43 | case WEBSOCKET_TEXT:
44 | if(len) { // if the message length was greater than zero
45 | ESP_LOGI(TAG, "got message length %i: %s", (int)len, msg);
46 | size_t xBytesSent = xMessageBufferSendFromISR(xMessageBufferToClient, msg, len, NULL);
47 | if (xBytesSent != len) {
48 | ESP_LOGE(TAG, "xMessageBufferSend fail");
49 | }
50 | }
51 | break;
52 | case WEBSOCKET_BIN:
53 | ESP_LOGI(TAG,"client %i sent binary message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
54 | break;
55 | case WEBSOCKET_PING:
56 | ESP_LOGI(TAG,"client %i pinged us with message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
57 | break;
58 | case WEBSOCKET_PONG:
59 | ESP_LOGI(TAG,"client %i responded to the ping",num);
60 | break;
61 | }
62 | }
63 |
64 | // serves any clients
65 | static void http_server(struct netconn *conn) {
66 | const static char* TAG = "http_server";
67 | const static char HTML_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/html\n\n";
68 | const static char ERROR_HEADER[] = "HTTP/1.1 404 Not Found\nContent-type: text/html\n\n";
69 | const static char JS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\n\n";
70 | const static char CSS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/css\n\n";
71 | //const static char PNG_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/png\n\n";
72 | const static char ICO_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/x-icon\n\n";
73 | //const static char PDF_HEADER[] = "HTTP/1.1 200 OK\nContent-type: application/pdf\n\n";
74 | //const static char EVENT_HEADER[] = "HTTP/1.1 200 OK\nContent-Type: text/event-stream\nCache-Control: no-cache\nretry: 3000\n\n";
75 | struct netbuf* inbuf;
76 | static char* buf;
77 | static uint16_t buflen;
78 | static err_t err;
79 |
80 | // default page
81 | extern const uint8_t root_html_start[] asm("_binary_root_html_start");
82 | extern const uint8_t root_html_end[] asm("_binary_root_html_end");
83 | const uint32_t root_html_len = root_html_end - root_html_start;
84 |
85 | // main.js
86 | extern const uint8_t main_js_start[] asm("_binary_main_js_start");
87 | extern const uint8_t main_js_end[] asm("_binary_main_js_end");
88 | const uint32_t main_js_len = main_js_end - main_js_start;
89 |
90 | // main.css
91 | extern const uint8_t main_css_start[] asm("_binary_main_css_start");
92 | extern const uint8_t main_css_end[] asm("_binary_main_css_end");
93 | const uint32_t main_css_len = main_css_end - main_css_start;
94 |
95 | // favicon.ico
96 | extern const uint8_t favicon_ico_start[] asm("_binary_favicon_ico_start");
97 | extern const uint8_t favicon_ico_end[] asm("_binary_favicon_ico_end");
98 | const uint32_t favicon_ico_len = favicon_ico_end - favicon_ico_start;
99 |
100 | // error page
101 | extern const uint8_t error_html_start[] asm("_binary_error_html_start");
102 | extern const uint8_t error_html_end[] asm("_binary_error_html_end");
103 | const uint32_t error_html_len = error_html_end - error_html_start;
104 |
105 | netconn_set_recvtimeout(conn,1000); // allow a connection timeout of 1 second
106 | ESP_LOGI(TAG,"reading from client...");
107 | err = netconn_recv(conn, &inbuf);
108 | ESP_LOGI(TAG,"read from client");
109 | if(err==ERR_OK) {
110 | netbuf_data(inbuf, (void**)&buf, &buflen);
111 | if(buf) {
112 |
113 | ESP_LOGD(TAG, "buf=[%s]", buf);
114 | // default page
115 | if (strstr(buf,"GET / ")
116 | && !strstr(buf,"Upgrade: websocket")) {
117 | ESP_LOGI(TAG,"Sending /");
118 | netconn_write(conn, HTML_HEADER, sizeof(HTML_HEADER)-1,NETCONN_NOCOPY);
119 | netconn_write(conn, root_html_start,root_html_len,NETCONN_NOCOPY);
120 | netconn_close(conn);
121 | netconn_delete(conn);
122 | netbuf_delete(inbuf);
123 | }
124 |
125 | // default page websocket
126 | else if(strstr(buf,"GET / ")
127 | && strstr(buf,"Upgrade: websocket")) {
128 | ESP_LOGI(TAG,"Requesting websocket on /");
129 | ws_server_add_client(conn,buf,buflen,"/",websocket_callback);
130 | netbuf_delete(inbuf);
131 | }
132 |
133 | else if(strstr(buf,"GET /main.js ")) {
134 | ESP_LOGI(TAG,"Sending /main.js");
135 | netconn_write(conn, JS_HEADER, sizeof(JS_HEADER)-1,NETCONN_NOCOPY);
136 | netconn_write(conn, main_js_start, main_js_len,NETCONN_NOCOPY);
137 | netconn_close(conn);
138 | netconn_delete(conn);
139 | netbuf_delete(inbuf);
140 | }
141 |
142 | else if(strstr(buf,"GET /main.css ")) {
143 | ESP_LOGI(TAG,"Sending /main.css");
144 | netconn_write(conn, CSS_HEADER, sizeof(CSS_HEADER)-1,NETCONN_NOCOPY);
145 | netconn_write(conn, main_css_start, main_css_len,NETCONN_NOCOPY);
146 | netconn_close(conn);
147 | netconn_delete(conn);
148 | netbuf_delete(inbuf);
149 | }
150 |
151 | else if(strstr(buf,"GET /favicon.ico ")) {
152 | ESP_LOGI(TAG,"Sending favicon.ico");
153 | netconn_write(conn,ICO_HEADER,sizeof(ICO_HEADER)-1,NETCONN_NOCOPY);
154 | netconn_write(conn,favicon_ico_start,favicon_ico_len,NETCONN_NOCOPY);
155 | netconn_close(conn);
156 | netconn_delete(conn);
157 | netbuf_delete(inbuf);
158 | }
159 |
160 | else if(strstr(buf,"GET /")) {
161 | ESP_LOGE(TAG,"Unknown request, sending error page: %s",buf);
162 | netconn_write(conn, ERROR_HEADER, sizeof(ERROR_HEADER)-1,NETCONN_NOCOPY);
163 | netconn_write(conn, error_html_start, error_html_len,NETCONN_NOCOPY);
164 | netconn_close(conn);
165 | netconn_delete(conn);
166 | netbuf_delete(inbuf);
167 | }
168 |
169 | else {
170 | ESP_LOGE(TAG,"Unknown request");
171 | netconn_close(conn);
172 | netconn_delete(conn);
173 | netbuf_delete(inbuf);
174 | }
175 | }
176 | else {
177 | ESP_LOGI(TAG,"Unknown request (empty?...)");
178 | netconn_close(conn);
179 | netconn_delete(conn);
180 | netbuf_delete(inbuf);
181 | }
182 | }
183 | else { // if err==ERR_OK
184 | ESP_LOGI(TAG,"error on read, closing connection");
185 | netconn_close(conn);
186 | netconn_delete(conn);
187 | netbuf_delete(inbuf);
188 | }
189 | }
190 |
191 | // receives clients from queue, handles them
192 | void server_handle_task(void* pvParameters) {
193 | const static char* TAG = "server_handle_task";
194 | struct netconn* conn;
195 | ESP_LOGI(TAG,"task starting");
196 | for(;;) {
197 | xQueueReceive(client_queue,&conn,portMAX_DELAY);
198 | if(!conn) continue;
199 | http_server(conn);
200 | }
201 | vTaskDelete(NULL);
202 | }
203 |
204 | // handles clients when they first connect. passes to a queue
205 | void server_task(void* pvParameters) {
206 | const static char* TAG = "server_task";
207 | char *task_parameter = (char *)pvParameters;
208 | ESP_LOGI(TAG, "Start task_parameter=%s", task_parameter);
209 | char url[64];
210 | sprintf(url, "http://%s", task_parameter);
211 | ESP_LOGI(TAG, "Starting server on %s", url);
212 |
213 | struct netconn *conn, *newconn;
214 | static err_t err;
215 | client_queue = xQueueCreate(client_queue_size,sizeof(struct netconn*));
216 | configASSERT( client_queue );
217 |
218 |
219 | UBaseType_t PriorityGet = uxTaskPriorityGet(NULL);
220 | ESP_LOGI(TAG, "PriorityGet=%d", PriorityGet);
221 | xTaskCreate(&server_handle_task, "server_handle_task", 1024*3, NULL, PriorityGet, NULL);
222 |
223 |
224 | conn = netconn_new(NETCONN_TCP);
225 | netconn_bind(conn,NULL,80);
226 | netconn_listen(conn);
227 | ESP_LOGI(TAG,"server listening");
228 | do {
229 | err = netconn_accept(conn, &newconn);
230 | ESP_LOGI(TAG,"new client");
231 | if(err == ERR_OK) {
232 | xQueueSendToBack(client_queue,&newconn,portMAX_DELAY);
233 | //http_server(newconn);
234 | }
235 | } while(err == ERR_OK);
236 | netconn_close(conn);
237 | netconn_delete(conn);
238 | ESP_LOGE(TAG,"task ending, rebooting board");
239 | esp_restart();
240 | }
241 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # esp-idf-web-chart
2 | This is a demonstration of __real-time data visualization__ using a web browser.
3 | The purpose of this project is to demonstrate how to use components that enable real-time data visualization.
4 | Although it use as data to display ADC converted values, it can also be applied to data from sensors such as thermometers and hygrometers.
5 |
6 | The ESP32 has two ADCs: ADC1 and ADC2.
7 | You can use these to convert analog values to digital values.
8 | The analog values change dynamically and are suitable for this demonstration.
9 | This project uses ADC1.
10 |
11 | - Using Canvas Gauge
12 | 
13 | 
14 | 
15 |
16 | - Using Chartjs-Plugin-Streaming
17 | 
18 |
19 | - Using Plotly
20 | 
21 | 
22 |
23 | - Using Epoch
24 | 
25 |
26 | - Using Seven Segment Display
27 | 
28 |
29 | # Software requirements
30 | ESP-IDF V5.0 or later.
31 | ESP-IDF V4.4 release branch reached EOL in July 2024.
32 | ESP-IDF V5.1 is required when using ESP32-C6.
33 | I used [this](https://github.com/Molorius/esp32-websocket) component.
34 | This component can communicate directly with the browser.
35 |
36 | # Installation
37 | ```
38 | git clone https://github.com/nopnop2002/esp-idf-web-chart
39 | cd esp-idf-web-chart/RadialGauge/
40 | idf.py set-target {esp32/esp32s2/esp32s3/esp32c2/esp32c3/esp32c6}
41 | idf.py menuconfig
42 | idf.py flash monitor
43 | ```
44 |
45 | # Configuration
46 | 
47 | 
48 |
49 |
50 | ## WiFi Setting
51 | Set the information of your access point.
52 | 
53 |
54 | You can connect using the mDNS hostname instead of the IP address.
55 | 
56 |
57 | ## ADC Setting
58 | Set the information of gpio for analog input.
59 | 
60 |
61 | It is possible to monitor 3 channels at the same time.
62 | 
63 |
64 | Analog input gpio for ESP32 is GPIO32 ~ GPIO39. 12Bits width.
65 | Analog input gpio for ESP32S2 is GPIO01 ~ GPIO10. 13Bits width.
66 | Analog input gpio for ESP32S3 is GPIO01 ~ GPIO10. 12Bits width.
67 | Analog input gpio for ESP32C2 is GPIO00 ~ GPIO04. 12Bits width.
68 | Analog input gpio for ESP32C3 is GPIO00 ~ GPIO04. 12Bits width.
69 | Analog input gpio for ESP32C6 is GPIO00 ~ GPIO06. 12Bits width.
70 |
71 | # ADC Attenuation
72 | This project uses ADC_ATTEN_DB_12(12dB) for attenuation.
73 | 12dB attenuation (ADC_ATTEN_DB_12) gives full-scale voltage 3.9V.
74 | But the range that can be measured accurately is as follows:
75 | - Measurable input voltage range for ESP32 is 150 mV ~ 2450 mV.
76 | - Measurable input voltage range for ESP32S2 is 0 mV ~ 2500 mV.
77 | - Measurable input voltage range for ESP32S3 is 0 mV ~ 3100 mV.
78 | - Measurable input voltage range for ESP32C3 is 0 mV ~ 2500 mV.
79 | - Measurable input voltage range for ESP32C2 is 0 mV ~ 2800 mV.
80 |
81 |
82 | # Analog source
83 | Connect ESP32 and Analog source using wire cable.
84 | I used a variable resistor for testing.
85 | ```
86 | +---------------------------+
87 | | variable resistor |
88 | ESP32 3.3V -----------------------------+ Ra of variable resistor |
89 | | |
90 | | |
91 | ESP32 GPIO32 -------------------------+---+ Vout of variable resistor |
92 | | | |
93 | R1 R2 R3 | | |
94 | ESP32 GND ----^^^--+--^^^--+--^^^--+ | |
95 | | | | |
96 | | | | |
97 | ESP32 GPIO33 ---------+ | | |
98 | | | |
99 | | | |
100 | ESP32 GPIO34 -----------------+ | |
101 | | |
102 | | |
103 | ESP32 GND -----------------------------+ Rb of variable resistor |
104 | | |
105 | +---------------------------+
106 | ```
107 |
108 | # Launch a web browser
109 | Enter the following in the address bar of your web browser.
110 |
111 | ```
112 | http:://{IP of ESP32}/
113 | or
114 | http://esp32-server.local/
115 | ```
116 |
117 | # How to display your sensor data
118 | Modify [this](https://github.com/nopnop2002/esp-idf-web-chart/blob/main/RadialGauge/main/web_client.c#L231) block to read data from your sensor.
119 | The ```timer-request``` is notified by the timer every second.
120 | ```
121 | if ( strcmp (id, "timer-request") == 0) {
122 | // read from sensor data to voltage1, voltage2, voltage3
123 | sprintf(outBuffer,"DATA%c%d%c%d%c%d", DEL, voltage1, DEL, voltage2, DEL, voltage3);
124 | ws_server_send_text_all(outBuffer,strlen(outBuffer));
125 | } // end if
126 | ```
127 |
128 | # WEB Pages
129 | WEB pages are stored in the html folder.
130 | You can change it as you like.
131 |
--------------------------------------------------------------------------------
/RadialGauge/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The following five lines of boilerplate have to be in your project's
2 | # CMakeLists in this exact order for cmake to work correctly
3 | cmake_minimum_required(VERSION 3.5)
4 |
5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6 | project(web-analog)
7 |
--------------------------------------------------------------------------------
/RadialGauge/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 nopnop2002
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/RadialGauge/README.md:
--------------------------------------------------------------------------------
1 | # Radial Gauge display using Canvas Gauge
2 | 
3 |
4 | I used [this](https://canvas-gauges.com/) for gauge display.
5 | You can easily change the gauge design.
6 |
7 |
--------------------------------------------------------------------------------
/RadialGauge/html/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ESP32 Error 404
5 |
6 |
7 |
8 |
9 |
10 |
11 | Error 404
12 | Unknown page. Return home.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/RadialGauge/html/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nopnop2002/esp-idf-web-chart/ce073d46522b28e6a06e84bd34ece938afb5857a/RadialGauge/html/favicon.ico
--------------------------------------------------------------------------------
/RadialGauge/html/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | Your favorite style is defined here.
3 | */
4 |
--------------------------------------------------------------------------------
/RadialGauge/html/main.js:
--------------------------------------------------------------------------------
1 | //document.getElementById("datetime").innerHTML = "WebSocket is not connected";
2 |
3 | var websocket = new WebSocket('ws://'+location.hostname+'/');
4 | var meter1 = 0;
5 | var meter2 = 0;
6 | var meter3 = 0;
7 |
8 |
9 | function sendText(name) {
10 | console.log('sendText');
11 | var data = {};
12 | data["id"] = name;
13 | console.log('data=', data);
14 | json_data = JSON.stringify(data);
15 | console.log('json_data=' + json_data);
16 | websocket.send(json_data);
17 | }
18 |
19 | websocket.onopen = function(evt) {
20 | console.log('WebSocket connection opened');
21 | var data = {};
22 | data["id"] = "init";
23 | console.log('data=', data);
24 | json_data = JSON.stringify(data);
25 | console.log('json_data=' + json_data);
26 | websocket.send(json_data);
27 | //document.getElementById("datetime").innerHTML = "WebSocket is connected!";
28 | }
29 |
30 | websocket.onmessage = function(evt) {
31 | var msg = evt.data;
32 | console.log("msg=" + msg);
33 | var values = msg.split('\4'); // \4 is EOT
34 | //console.log("values=" + values);
35 | switch(values[0]) {
36 | case 'HEAD':
37 | console.log("HEAD values[1]=" + values[1]);
38 | var h1 = document.getElementById( 'header' );
39 | h1.textContent = values[1];
40 | break;
41 |
42 | case 'METER':
43 | //console.log("gauge1=" + Object.keys(gauge1.options));
44 | //console.log("gauge1.options.units=" + gauge1.options.units);
45 | console.log("METER values[1]=" + values[1]);
46 | console.log("METER values[2]=" + values[2]);
47 | console.log("METER values[3]=" + values[3]);
48 | if (values[1] != "") {
49 | gauge1.options.units = values[1];
50 | document.getElementById("canvas1").style.display = "inline-block";
51 | meter1 = 1;
52 | }
53 | if (values[2] != "") {
54 | gauge2.options.units = values[2];
55 | document.getElementById("canvas2").style.display = "inline-block";
56 | meter2 = 1;
57 | }
58 | if (values[3] != "") {
59 | gauge3.options.units = values[3];
60 | document.getElementById("canvas3").style.display = "inline-block";
61 | meter3 = 1;
62 | }
63 | break;
64 |
65 | case 'DATA':
66 | console.log("DATA values[1]=" + values[1]);
67 | var voltage1 = parseInt(values[1], 10);
68 | gauge1.value = voltage1;
69 | gauge1.update({ valueText: values[1] });
70 | if (meter2) {
71 | console.log("DATA values[2]=" + values[2]);
72 | var voltage2 = parseInt(values[2], 10);
73 | gauge2.value = voltage2;
74 | gauge2.update({ valueText: values[2] });
75 | }
76 | if (meter3) {
77 | console.log("DATA values[3]=" + values[3]);
78 | var voltage3 = parseInt(values[3], 10);
79 | gauge3.value = voltage3;
80 | gauge3.update({ valueText: values[3] });
81 | }
82 | break;
83 |
84 | default:
85 | break;
86 | }
87 | }
88 |
89 | websocket.onclose = function(evt) {
90 | console.log('Websocket connection closed');
91 | //document.getElementById("datetime").innerHTML = "WebSocket closed";
92 | }
93 |
94 | websocket.onerror = function(evt) {
95 | console.log('Websocket error: ' + evt);
96 | //document.getElementById("datetime").innerHTML = "WebSocket error????!!!1!!";
97 | }
98 |
--------------------------------------------------------------------------------
/RadialGauge/html/root.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Canvas Gauge
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/RadialGauge/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "main.c" "web_server.c" "web_client.c"
2 | INCLUDE_DIRS "."
3 | EMBED_FILES "../html/error.html"
4 | "../html/favicon.ico"
5 | "../html/main.js"
6 | "../html/root.html"
7 | "../html/main.css")
8 |
--------------------------------------------------------------------------------
/RadialGauge/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "Application configuration"
2 |
3 | config GPIO_RANGE_MIN
4 | int
5 | default 32 if IDF_TARGET_ESP32
6 | default 1 if IDF_TARGET_ESP32S2
7 | default 1 if IDF_TARGET_ESP32S3
8 | default 0 if IDF_TARGET_ESP32C2
9 | default 0 if IDF_TARGET_ESP32C3
10 | default 0 if IDF_TARGET_ESP32C6
11 |
12 | config GPIO_RANGE_MAX
13 | int
14 | default 39 if IDF_TARGET_ESP32
15 | default 10 if IDF_TARGET_ESP32S2
16 | default 10 if IDF_TARGET_ESP32S3
17 | default 4 if IDF_TARGET_ESP32C2
18 | default 4 if IDF_TARGET_ESP32C3
19 | default 6 if IDF_TARGET_ESP32C6
20 |
21 | menu "WiFi Setting"
22 |
23 | config ESP_WIFI_SSID
24 | string "WiFi SSID"
25 | default "myssid"
26 | help
27 | SSID (network name) to connect to.
28 |
29 | config ESP_WIFI_PASSWORD
30 | string "WiFi Password"
31 | default "mypassword"
32 | help
33 | WiFi password (WPA or WPA2) to connect to.
34 |
35 | config ESP_MAXIMUM_RETRY
36 | int "Maximum retry"
37 | default 5
38 | help
39 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
40 |
41 | config MDNS_HOSTNAME
42 | string "mDNS Hostname"
43 | default "esp32-server"
44 | help
45 | The mDNS host name used by the ESP32.
46 |
47 | endmenu
48 |
49 | menu "ADC Setting"
50 |
51 | config METER1_GPIO
52 | int "GPIO for ADC1"
53 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
54 | default 32 if IDF_TARGET_ESP32
55 | default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
56 | default 0 # C3 and others
57 | help
58 | ADC1_CHANNEL number.
59 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
60 | On the ESP32, 8 channels: GPIO32 - GPIO39.
61 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
62 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
63 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
64 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
65 |
66 | config ENABLE_METER2
67 | bool "Enable METER2"
68 | default n
69 | help
70 | Enable Meter2.
71 |
72 | config METER2_GPIO
73 | depends on ENABLE_METER2
74 | int "GPIO for METER2"
75 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
76 | default 33 if IDF_TARGET_ESP32
77 | default 2 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
78 | default 1 # C3 and others
79 | help
80 | ADC1_CHANNEL number.
81 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
82 | On the ESP32, 8 channels: GPIO32 - GPIO39.
83 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
84 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
85 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
86 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
87 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
88 |
89 | config ENABLE_METER3
90 | bool "Enable METER3"
91 | default n
92 | help
93 | Enable Meter3.
94 |
95 | config METER3_GPIO
96 | depends on ENABLE_METER3
97 | int "GPIO for METER3"
98 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
99 | default 34 if IDF_TARGET_ESP32
100 | default 3 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
101 | default 2 # C3 and others
102 | help
103 | ADC1_CHANNEL number.
104 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
105 | On the ESP32, 8 channels: GPIO32 - GPIO39.
106 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
107 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
108 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
109 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
110 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
111 |
112 | config ADC_CYCLE
113 | int "ADC measurement cycle tick"
114 | range 100 1000
115 | default 100
116 | help
117 | ADC measurement cycle tick.
118 |
119 | config ENABLE_STDOUT
120 | bool "Enable STDOUT"
121 | default n
122 | help
123 | Enable STDOUT.
124 |
125 | endmenu
126 |
127 | endmenu
128 |
129 |
--------------------------------------------------------------------------------
/RadialGauge/main/component.mk:
--------------------------------------------------------------------------------
1 | COMPONENT_EMBED_FILES := ../html/error.html
2 | COMPONENT_EMBED_FILES += ../html/favicon.ico
3 | COMPONENT_EMBED_FILES += ../html/main.js
4 | COMPONENT_EMBED_FILES += ../html/root.html
5 | COMPONENT_EMBED_FILES += ../html/bulma.css
6 | COMPONENT_EMBED_FILES += ../html/main.css
7 |
--------------------------------------------------------------------------------
/RadialGauge/main/idf_component.yml:
--------------------------------------------------------------------------------
1 | ## IDF Component Manager Manifest File
2 | dependencies:
3 | Molorius/esp32-websocket:
4 | git: https://github.com/Molorius/esp32-websocket
5 | espressif/mdns:
6 | version: "^1.0.3"
7 | rules:
8 | - if: "idf_version >=5.0"
9 |
--------------------------------------------------------------------------------
/RadialGauge/main/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/event_groups.h"
16 | #include "freertos/message_buffer.h"
17 |
18 | #include "esp_wifi.h"
19 | #include "esp_log.h"
20 | #include "nvs_flash.h"
21 | #include "mdns.h"
22 |
23 | #include "websocket_server.h"
24 |
25 | MessageBufferHandle_t xMessageBufferToClient;
26 |
27 | /* FreeRTOS event group to signal when we are connected*/
28 | static EventGroupHandle_t s_wifi_event_group;
29 |
30 | /* The event group allows multiple bits for each event, but we only care about two events:
31 | * - we are connected to the AP with an IP
32 | * - we failed to connect after the maximum amount of retries */
33 | #define WIFI_CONNECTED_BIT BIT0
34 | #define WIFI_FAIL_BIT BIT1
35 |
36 | static const char *TAG = "main";
37 |
38 | static int s_retry_num = 0;
39 |
40 | static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
41 | {
42 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
43 | esp_wifi_connect();
44 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
45 | if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
46 | esp_wifi_connect();
47 | s_retry_num++;
48 | ESP_LOGI(TAG, "retry to connect to the AP");
49 | } else {
50 | xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
51 | }
52 | ESP_LOGI(TAG,"connect to the AP fail");
53 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
54 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
55 | ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
56 | s_retry_num = 0;
57 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
58 | }
59 | }
60 |
61 | void wifi_init_sta(void)
62 | {
63 | s_wifi_event_group = xEventGroupCreate();
64 |
65 | ESP_ERROR_CHECK(esp_netif_init());
66 |
67 | ESP_ERROR_CHECK(esp_event_loop_create_default());
68 | esp_netif_create_default_wifi_sta();
69 |
70 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
71 | ESP_ERROR_CHECK(esp_wifi_init(&cfg));
72 |
73 | esp_event_handler_instance_t instance_any_id;
74 | esp_event_handler_instance_t instance_got_ip;
75 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
76 | ESP_EVENT_ANY_ID,
77 | &event_handler,
78 | NULL,
79 | &instance_any_id));
80 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
81 | IP_EVENT_STA_GOT_IP,
82 | &event_handler,
83 | NULL,
84 | &instance_got_ip));
85 |
86 | wifi_config_t wifi_config = {
87 | .sta = {
88 | .ssid = CONFIG_ESP_WIFI_SSID,
89 | .password = CONFIG_ESP_WIFI_PASSWORD,
90 | /* Setting a password implies station will connect to all security modes including WEP/WPA.
91 | * However these modes are deprecated and not advisable to be used. Incase your Access point
92 | * doesn't support WPA2, these mode can be enabled by commenting below line */
93 | .threshold.authmode = WIFI_AUTH_WPA2_PSK,
94 |
95 | .pmf_cfg = {
96 | .capable = true,
97 | .required = false
98 | },
99 | },
100 | };
101 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
102 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
103 | ESP_ERROR_CHECK(esp_wifi_start() );
104 |
105 | ESP_LOGI(TAG, "wifi_init_sta finished.");
106 |
107 | /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
108 | * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
109 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
110 | WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
111 | pdFALSE,
112 | pdFALSE,
113 | portMAX_DELAY);
114 |
115 | /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
116 | * happened. */
117 | if (bits & WIFI_CONNECTED_BIT) {
118 | ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
119 | } else if (bits & WIFI_FAIL_BIT) {
120 | ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
121 | } else {
122 | ESP_LOGE(TAG, "UNEXPECTED EVENT");
123 | }
124 |
125 | /* The event will not be processed after unregister */
126 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
127 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
128 | vEventGroupDelete(s_wifi_event_group);
129 | }
130 |
131 | void initialise_mdns(void)
132 | {
133 | //initialize mDNS
134 | ESP_ERROR_CHECK( mdns_init() );
135 | //set mDNS hostname (required if you want to advertise services)
136 | ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
137 | ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
138 |
139 | //initialize service
140 | ESP_ERROR_CHECK( mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) );
141 |
142 | #if 0
143 | //set default mDNS instance name
144 | ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
145 | #endif
146 | }
147 |
148 | void client_task(void* pvParameters);
149 | void server_task(void* pvParameters);
150 |
151 | void app_main() {
152 | // Initialize NVS
153 | esp_err_t ret = nvs_flash_init();
154 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
155 | ESP_ERROR_CHECK(nvs_flash_erase());
156 | ret = nvs_flash_init();
157 | }
158 | ESP_ERROR_CHECK(ret);
159 |
160 | // Initialize WiFi
161 | wifi_init_sta();
162 |
163 | // Initialize mDNS
164 | initialise_mdns();
165 |
166 | // Create Message Buffer
167 | xMessageBufferToClient = xMessageBufferCreate(1024);
168 | configASSERT( xMessageBufferToClient );
169 |
170 | // Get the local IP address
171 | esp_netif_ip_info_t ip_info;
172 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
173 | char cparam0[64];
174 | sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
175 |
176 | // Start web socket server
177 | ws_server_start();
178 |
179 | // Start web server
180 | xTaskCreate(&server_task, "server_task", 1024*4, (void *)cparam0, 5, NULL);
181 |
182 | // Start web client
183 | xTaskCreate(&client_task, "client_task", 1024*4, NULL, 5, NULL);
184 |
185 | vTaskDelay(100);
186 | }
187 |
--------------------------------------------------------------------------------
/RadialGauge/main/web_server.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/message_buffer.h"
16 | #include "esp_log.h"
17 |
18 | #include "websocket_server.h"
19 |
20 | static QueueHandle_t client_queue;
21 | extern MessageBufferHandle_t xMessageBufferToClient;
22 |
23 | const static int client_queue_size = 10;
24 |
25 | // handles websocket events
26 | void websocket_callback(uint8_t num,WEBSOCKET_TYPE_t type,char* msg,uint64_t len) {
27 | const static char* TAG = "websocket_callback";
28 | //int value;
29 |
30 | switch(type) {
31 | case WEBSOCKET_CONNECT:
32 | ESP_LOGI(TAG,"client %i connected!",num);
33 | break;
34 | case WEBSOCKET_DISCONNECT_EXTERNAL:
35 | ESP_LOGI(TAG,"client %i sent a disconnect message",num);
36 | break;
37 | case WEBSOCKET_DISCONNECT_INTERNAL:
38 | ESP_LOGI(TAG,"client %i was disconnected",num);
39 | break;
40 | case WEBSOCKET_DISCONNECT_ERROR:
41 | ESP_LOGI(TAG,"client %i was disconnected due to an error",num);
42 | break;
43 | case WEBSOCKET_TEXT:
44 | if(len) { // if the message length was greater than zero
45 | ESP_LOGI(TAG, "got message length %i: %s", (int)len, msg);
46 | size_t xBytesSent = xMessageBufferSendFromISR(xMessageBufferToClient, msg, len, NULL);
47 | if (xBytesSent != len) {
48 | ESP_LOGE(TAG, "xMessageBufferSend fail");
49 | }
50 | }
51 | break;
52 | case WEBSOCKET_BIN:
53 | ESP_LOGI(TAG,"client %i sent binary message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
54 | break;
55 | case WEBSOCKET_PING:
56 | ESP_LOGI(TAG,"client %i pinged us with message of size %"PRIu32":\n%s",num,(uint32_t)len,msg);
57 | break;
58 | case WEBSOCKET_PONG:
59 | ESP_LOGI(TAG,"client %i responded to the ping",num);
60 | break;
61 | }
62 | }
63 |
64 | // serves any clients
65 | static void http_server(struct netconn *conn) {
66 | const static char* TAG = "http_server";
67 | const static char HTML_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/html\n\n";
68 | const static char ERROR_HEADER[] = "HTTP/1.1 404 Not Found\nContent-type: text/html\n\n";
69 | const static char JS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\n\n";
70 | const static char CSS_HEADER[] = "HTTP/1.1 200 OK\nContent-type: text/css\n\n";
71 | //const static char PNG_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/png\n\n";
72 | const static char ICO_HEADER[] = "HTTP/1.1 200 OK\nContent-type: image/x-icon\n\n";
73 | //const static char PDF_HEADER[] = "HTTP/1.1 200 OK\nContent-type: application/pdf\n\n";
74 | //const static char EVENT_HEADER[] = "HTTP/1.1 200 OK\nContent-Type: text/event-stream\nCache-Control: no-cache\nretry: 3000\n\n";
75 | struct netbuf* inbuf;
76 | static char* buf;
77 | static uint16_t buflen;
78 | static err_t err;
79 |
80 | // default page
81 | extern const uint8_t root_html_start[] asm("_binary_root_html_start");
82 | extern const uint8_t root_html_end[] asm("_binary_root_html_end");
83 | const uint32_t root_html_len = root_html_end - root_html_start;
84 |
85 | // main.js
86 | extern const uint8_t main_js_start[] asm("_binary_main_js_start");
87 | extern const uint8_t main_js_end[] asm("_binary_main_js_end");
88 | const uint32_t main_js_len = main_js_end - main_js_start;
89 |
90 | // main.css
91 | extern const uint8_t main_css_start[] asm("_binary_main_css_start");
92 | extern const uint8_t main_css_end[] asm("_binary_main_css_end");
93 | const uint32_t main_css_len = main_css_end - main_css_start;
94 |
95 | // favicon.ico
96 | extern const uint8_t favicon_ico_start[] asm("_binary_favicon_ico_start");
97 | extern const uint8_t favicon_ico_end[] asm("_binary_favicon_ico_end");
98 | const uint32_t favicon_ico_len = favicon_ico_end - favicon_ico_start;
99 |
100 | // error page
101 | extern const uint8_t error_html_start[] asm("_binary_error_html_start");
102 | extern const uint8_t error_html_end[] asm("_binary_error_html_end");
103 | const uint32_t error_html_len = error_html_end - error_html_start;
104 |
105 | netconn_set_recvtimeout(conn,1000); // allow a connection timeout of 1 second
106 | ESP_LOGI(TAG,"reading from client...");
107 | err = netconn_recv(conn, &inbuf);
108 | ESP_LOGI(TAG,"read from client");
109 | if(err==ERR_OK) {
110 | netbuf_data(inbuf, (void**)&buf, &buflen);
111 | if(buf) {
112 |
113 | ESP_LOGD(TAG, "buf=[%s]", buf);
114 | // default page
115 | if (strstr(buf,"GET / ")
116 | && !strstr(buf,"Upgrade: websocket")) {
117 | ESP_LOGI(TAG,"Sending /");
118 | netconn_write(conn, HTML_HEADER, sizeof(HTML_HEADER)-1,NETCONN_NOCOPY);
119 | netconn_write(conn, root_html_start,root_html_len,NETCONN_NOCOPY);
120 | netconn_close(conn);
121 | netconn_delete(conn);
122 | netbuf_delete(inbuf);
123 | }
124 |
125 | // default page websocket
126 | else if(strstr(buf,"GET / ")
127 | && strstr(buf,"Upgrade: websocket")) {
128 | ESP_LOGI(TAG,"Requesting websocket on /");
129 | ws_server_add_client(conn,buf,buflen,"/",websocket_callback);
130 | netbuf_delete(inbuf);
131 | }
132 |
133 | else if(strstr(buf,"GET /main.js ")) {
134 | ESP_LOGI(TAG,"Sending /main.js");
135 | netconn_write(conn, JS_HEADER, sizeof(JS_HEADER)-1,NETCONN_NOCOPY);
136 | netconn_write(conn, main_js_start, main_js_len,NETCONN_NOCOPY);
137 | netconn_close(conn);
138 | netconn_delete(conn);
139 | netbuf_delete(inbuf);
140 | }
141 |
142 | else if(strstr(buf,"GET /main.css ")) {
143 | ESP_LOGI(TAG,"Sending /main.css");
144 | netconn_write(conn, CSS_HEADER, sizeof(CSS_HEADER)-1,NETCONN_NOCOPY);
145 | netconn_write(conn, main_css_start, main_css_len,NETCONN_NOCOPY);
146 | netconn_close(conn);
147 | netconn_delete(conn);
148 | netbuf_delete(inbuf);
149 | }
150 |
151 | else if(strstr(buf,"GET /favicon.ico ")) {
152 | ESP_LOGI(TAG,"Sending favicon.ico");
153 | netconn_write(conn,ICO_HEADER,sizeof(ICO_HEADER)-1,NETCONN_NOCOPY);
154 | netconn_write(conn,favicon_ico_start,favicon_ico_len,NETCONN_NOCOPY);
155 | netconn_close(conn);
156 | netconn_delete(conn);
157 | netbuf_delete(inbuf);
158 | }
159 |
160 | else if(strstr(buf,"GET /")) {
161 | ESP_LOGE(TAG,"Unknown request, sending error page: %s",buf);
162 | netconn_write(conn, ERROR_HEADER, sizeof(ERROR_HEADER)-1,NETCONN_NOCOPY);
163 | netconn_write(conn, error_html_start, error_html_len,NETCONN_NOCOPY);
164 | netconn_close(conn);
165 | netconn_delete(conn);
166 | netbuf_delete(inbuf);
167 | }
168 |
169 | else {
170 | ESP_LOGE(TAG,"Unknown request");
171 | netconn_close(conn);
172 | netconn_delete(conn);
173 | netbuf_delete(inbuf);
174 | }
175 | }
176 | else {
177 | ESP_LOGI(TAG,"Unknown request (empty?...)");
178 | netconn_close(conn);
179 | netconn_delete(conn);
180 | netbuf_delete(inbuf);
181 | }
182 | }
183 | else { // if err==ERR_OK
184 | ESP_LOGI(TAG,"error on read, closing connection");
185 | netconn_close(conn);
186 | netconn_delete(conn);
187 | netbuf_delete(inbuf);
188 | }
189 | }
190 |
191 | // receives clients from queue, handles them
192 | void server_handle_task(void* pvParameters) {
193 | const static char* TAG = "server_handle_task";
194 | struct netconn* conn;
195 | ESP_LOGI(TAG,"task starting");
196 | for(;;) {
197 | xQueueReceive(client_queue,&conn,portMAX_DELAY);
198 | if(!conn) continue;
199 | http_server(conn);
200 | }
201 | vTaskDelete(NULL);
202 | }
203 |
204 | // handles clients when they first connect. passes to a queue
205 | void server_task(void* pvParameters) {
206 | const static char* TAG = "server_task";
207 | char *task_parameter = (char *)pvParameters;
208 | ESP_LOGI(TAG, "Start task_parameter=%s", task_parameter);
209 | char url[64];
210 | sprintf(url, "http://%s", task_parameter);
211 | ESP_LOGI(TAG, "Starting server on %s", url);
212 |
213 | struct netconn *conn, *newconn;
214 | static err_t err;
215 | client_queue = xQueueCreate(client_queue_size,sizeof(struct netconn*));
216 | configASSERT( client_queue );
217 |
218 |
219 | UBaseType_t PriorityGet = uxTaskPriorityGet(NULL);
220 | ESP_LOGI(TAG, "PriorityGet=%d", PriorityGet);
221 | xTaskCreate(&server_handle_task, "server_handle_task", 1024*3, NULL, PriorityGet, NULL);
222 |
223 |
224 | conn = netconn_new(NETCONN_TCP);
225 | netconn_bind(conn,NULL,80);
226 | netconn_listen(conn);
227 | ESP_LOGI(TAG,"server listening");
228 | do {
229 | err = netconn_accept(conn, &newconn);
230 | ESP_LOGI(TAG,"new client");
231 | if(err == ERR_OK) {
232 | xQueueSendToBack(client_queue,&newconn,portMAX_DELAY);
233 | //http_server(newconn);
234 | }
235 | } while(err == ERR_OK);
236 | netconn_close(conn);
237 | netconn_delete(conn);
238 | ESP_LOGE(TAG,"task ending, rebooting board");
239 | esp_restart();
240 | }
241 |
--------------------------------------------------------------------------------
/SevenSegment/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The following five lines of boilerplate have to be in your project's
2 | # CMakeLists in this exact order for cmake to work correctly
3 | cmake_minimum_required(VERSION 3.5)
4 |
5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6 | project(web-analog)
7 |
--------------------------------------------------------------------------------
/SevenSegment/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 nopnop2002
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/SevenSegment/README.md:
--------------------------------------------------------------------------------
1 | # SevenSegment view
2 | 
3 |
4 | I used [this](https://github.com/CodeDrome/seven-segment-display-javascript) for segment display.
5 | You can easily change the segment color and number of digits.
6 | 
7 | 
8 | 
9 | 
10 | 
11 | 
12 |
13 | The display unit can be changed from mV to V.
14 | 
15 | 
16 |
--------------------------------------------------------------------------------
/SevenSegment/html/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ESP32 Error 404
5 |
6 |
7 |
8 |
9 |
10 |
11 | Error 404
12 | Unknown page. Return home.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/SevenSegment/html/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nopnop2002/esp-idf-web-chart/ce073d46522b28e6a06e84bd34ece938afb5857a/SevenSegment/html/favicon.ico
--------------------------------------------------------------------------------
/SevenSegment/html/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | Your favorite style is defined here.
3 | */
4 |
--------------------------------------------------------------------------------
/SevenSegment/html/main.js:
--------------------------------------------------------------------------------
1 | //document.getElementById("datetime").innerHTML = "WebSocket is not connected";
2 |
3 | var websocket = new WebSocket('ws://'+location.hostname+'/');
4 | var meter1 = 0;
5 | var meter2 = 0;
6 | var meter3 = 0;
7 | var segment1 = new SevenSegmentDisplay("canvas1");
8 | var segment2 = new SevenSegmentDisplay("canvas2");
9 | var segment3 = new SevenSegmentDisplay("canvas3");
10 | var gpio1 = "";
11 | var gpio2 = "";
12 | var gpio3 = "";
13 | var uint = 1;
14 |
15 | function sendText(name) {
16 | console.log('sendText');
17 | var data = {};
18 | data["id"] = name;
19 | console.log('data=', data);
20 | json_data = JSON.stringify(data);
21 | console.log('json_data=' + json_data);
22 | websocket.send(json_data);
23 | }
24 |
25 | window.onload = function() {
26 | console.log("onload");
27 | // ColorScheme is 1 to 6
28 | segment1.ColorScheme = 2;
29 | segment1.DecimalPointType = 2;
30 | segment1.NumberOfDecimalPlaces = 0;
31 | segment1.NumberOfDigits = 4;
32 |
33 | segment2.ColorScheme = 3;
34 | segment2.DecimalPointType = 2;
35 | segment2.NumberOfDecimalPlaces = 0;
36 | segment2.NumberOfDigits = 4;
37 |
38 | segment3.ColorScheme = 4;
39 | segment3.DecimalPointType = 2;
40 | segment3.NumberOfDecimalPlaces = 0;
41 | segment3.NumberOfDigits = 4;
42 | };
43 |
44 | websocket.onopen = function(evt) {
45 | console.log('WebSocket connection opened');
46 | var data = {};
47 | data["id"] = "init";
48 | console.log('data=', data);
49 | json_data = JSON.stringify(data);
50 | console.log('json_data=' + json_data);
51 | websocket.send(json_data);
52 | //document.getElementById("datetime").innerHTML = "WebSocket is connected!";
53 | }
54 |
55 | websocket.onmessage = function(evt) {
56 | var msg = evt.data;
57 | console.log("msg=" + msg);
58 | var values = msg.split('\4'); // \4 is EOT
59 | //console.log("values=" + values);
60 | switch(values[0]) {
61 | case 'HEAD':
62 | console.log("HEAD values[1]=" + values[1]);
63 | var h1 = document.getElementById( 'header' );
64 | h1.textContent = values[1];
65 | break;
66 |
67 | case 'METER':
68 | console.log("METER values[1]=" + values[1]);
69 | console.log("METER values[2]=" + values[2]);
70 | console.log("METER values[3]=" + values[3]);
71 | if (values[1] == "") {
72 | document.getElementById("label1").style.display = "none";
73 | document.getElementById("canvas1").style.display = "none";
74 | } else {
75 | meter1 = 1;
76 | gpio1 = values[1];
77 | document.getElementById("label1").style.display = "inline-block";
78 | document.getElementById("label1").innerText = gpio1 + " [mV]";
79 | document.getElementById("canvas1").style.display = "inline-block";
80 | }
81 | if (values[2] == "") {
82 | document.getElementById("label2").style.display = "none";
83 | document.getElementById("canvas2").style.display = "none";
84 | } else {
85 | meter2 = 1;
86 | gpio2 = values[2];
87 | document.getElementById("label2").style.display = "inline-block";
88 | document.getElementById("label2").innerText = gpio2 + " [mV]";
89 | document.getElementById("canvas2").style.display = "inline-block";
90 | }
91 | if (values[3] == "") {
92 | document.getElementById("label3").style.display = "none";
93 | document.getElementById("canvas3").style.display = "none";
94 | } else {
95 | meter3 = 1;
96 | gpio3 = values[3];
97 | document.getElementById("label3").style.display = "inline-block";
98 | document.getElementById("label3").innerText = gpio3 + " [mV]";
99 | document.getElementById("canvas3").style.display = "inline-block";
100 | }
101 | break;
102 |
103 | case 'UNIT':
104 | console.log("UNIT");
105 | uint = 1000;
106 | segment1.NumberOfDecimalPlaces = 3;
107 | segment2.NumberOfDecimalPlaces = 3;
108 | segment3.NumberOfDecimalPlaces = 3;
109 | document.getElementById("label1").innerText = gpio1 + " [V]";
110 | document.getElementById("label2").innerText = gpio2 + " [V]";
111 | document.getElementById("label3").innerText = gpio3 + " [V]";
112 | break;
113 |
114 | case 'DATA':
115 | console.log("DATA values[1]=" + values[1]);
116 | var voltage1 = parseInt(values[1], 10);
117 | segment1.Value = voltage1 / uint;
118 | if (meter2) {
119 | console.log("DATA values[2]=" + values[2]);
120 | var voltage2 = parseInt(values[2], 10);
121 | segment2.Value = voltage2 / uint;
122 | }
123 | if (meter3) {
124 | console.log("DATA values[3]=" + values[3]);
125 | var voltage3 = parseInt(values[3], 10);
126 | segment3.Value = voltage3 / uint;
127 | }
128 | break;
129 |
130 | default:
131 | break;
132 | }
133 | }
134 |
135 | websocket.onclose = function(evt) {
136 | console.log('Websocket connection closed');
137 | //document.getElementById("datetime").innerHTML = "WebSocket closed";
138 | }
139 |
140 | websocket.onerror = function(evt) {
141 | console.log('Websocket error: ' + evt);
142 | //document.getElementById("datetime").innerHTML = "WebSocket error????!!!1!!";
143 | }
144 |
--------------------------------------------------------------------------------
/SevenSegment/html/root.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 | Seven Segments
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
30 |
31 |
32 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/SevenSegment/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "main.c" "web_server.c" "web_client.c"
2 | INCLUDE_DIRS "."
3 | EMBED_FILES "../html/error.html"
4 | "../html/favicon.ico"
5 | "../html/seven_segment_display.js"
6 | "../html/main.js"
7 | "../html/root.html"
8 | "../html/main.css")
9 |
--------------------------------------------------------------------------------
/SevenSegment/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "Application configuration"
2 |
3 | config GPIO_RANGE_MIN
4 | int
5 | default 32 if IDF_TARGET_ESP32
6 | default 1 if IDF_TARGET_ESP32S2
7 | default 1 if IDF_TARGET_ESP32S3
8 | default 0 if IDF_TARGET_ESP32C2
9 | default 0 if IDF_TARGET_ESP32C3
10 | default 0 if IDF_TARGET_ESP32C6
11 |
12 | config GPIO_RANGE_MAX
13 | int
14 | default 39 if IDF_TARGET_ESP32
15 | default 10 if IDF_TARGET_ESP32S2
16 | default 10 if IDF_TARGET_ESP32S3
17 | default 4 if IDF_TARGET_ESP32C2
18 | default 4 if IDF_TARGET_ESP32C3
19 | default 6 if IDF_TARGET_ESP32C6
20 |
21 | menu "WiFi Setting"
22 |
23 | config ESP_WIFI_SSID
24 | string "WiFi SSID"
25 | default "myssid"
26 | help
27 | SSID (network name) to connect to.
28 |
29 | config ESP_WIFI_PASSWORD
30 | string "WiFi Password"
31 | default "mypassword"
32 | help
33 | WiFi password (WPA or WPA2) to connect to.
34 |
35 | config ESP_MAXIMUM_RETRY
36 | int "Maximum retry"
37 | default 5
38 | help
39 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
40 |
41 | config MDNS_HOSTNAME
42 | string "mDNS Hostname"
43 | default "esp32-server"
44 | help
45 | The mDNS host name used by the ESP32.
46 |
47 | endmenu
48 |
49 | menu "ADC Setting"
50 |
51 | config METER1_GPIO
52 | int "GPIO for ADC1"
53 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
54 | default 32 if IDF_TARGET_ESP32
55 | default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
56 | default 0 # C3 and others
57 | help
58 | ADC1_CHANNEL number.
59 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
60 | On the ESP32, 8 channels: GPIO32 - GPIO39.
61 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
62 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
63 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
64 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
65 |
66 | config ENABLE_METER2
67 | bool "Enable METER2"
68 | default n
69 | help
70 | Enable Meter2.
71 |
72 | config METER2_GPIO
73 | depends on ENABLE_METER2
74 | int "GPIO for METER2"
75 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
76 | default 33 if IDF_TARGET_ESP32
77 | default 2 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
78 | default 1 # C3 and others
79 | help
80 | ADC1_CHANNEL number.
81 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
82 | On the ESP32, 8 channels: GPIO32 - GPIO39.
83 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
84 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
85 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
86 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
87 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
88 |
89 | config ENABLE_METER3
90 | bool "Enable METER3"
91 | default n
92 | help
93 | Enable Meter3.
94 |
95 | config METER3_GPIO
96 | depends on ENABLE_METER3
97 | int "GPIO for METER3"
98 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
99 | default 34 if IDF_TARGET_ESP32
100 | default 3 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
101 | default 2 # C3 and others
102 | help
103 | ADC1_CHANNEL number.
104 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
105 | On the ESP32, 8 channels: GPIO32 - GPIO39.
106 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
107 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
108 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
109 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
110 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
111 |
112 | config ADC_CYCLE
113 | int "ADC measurement cycle tick"
114 | range 100 1000
115 | default 100
116 | help
117 | ADC measurement cycle tick.
118 |
119 | config ENABLE_STDOUT
120 | bool "Enable STDOUT"
121 | default n
122 | help
123 | Enable STDOUT.
124 |
125 | choice UNIT
126 | prompt "Unit to display"
127 | default UNIT_MV
128 | help
129 | Select Unit to display.
130 | config UNIT_MV
131 | bool "mV unit"
132 | help
133 | mV unit.
134 | config UNIT_V
135 | bool "V unit"
136 | endchoice
137 |
138 | endmenu
139 |
140 | endmenu
141 |
142 |
--------------------------------------------------------------------------------
/SevenSegment/main/component.mk:
--------------------------------------------------------------------------------
1 | COMPONENT_EMBED_FILES := ../html/error.html
2 | COMPONENT_EMBED_FILES += ../html/favicon.ico
3 | COMPONENT_EMBED_FILES += ../html/main.js
4 | COMPONENT_EMBED_FILES += ../html/root.html
5 | COMPONENT_EMBED_FILES += ../html/bulma.css
6 | COMPONENT_EMBED_FILES += ../html/main.css
7 |
--------------------------------------------------------------------------------
/SevenSegment/main/idf_component.yml:
--------------------------------------------------------------------------------
1 | ## IDF Component Manager Manifest File
2 | dependencies:
3 | Molorius/esp32-websocket:
4 | git: https://github.com/Molorius/esp32-websocket
5 | espressif/mdns:
6 | version: "^1.0.3"
7 | rules:
8 | - if: "idf_version >=5.0"
9 |
--------------------------------------------------------------------------------
/SevenSegment/main/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/event_groups.h"
16 | #include "freertos/message_buffer.h"
17 |
18 | #include "esp_wifi.h"
19 | #include "esp_log.h"
20 | #include "nvs_flash.h"
21 | #include "mdns.h"
22 |
23 | #include "websocket_server.h"
24 |
25 | MessageBufferHandle_t xMessageBufferToClient;
26 |
27 | /* FreeRTOS event group to signal when we are connected*/
28 | static EventGroupHandle_t s_wifi_event_group;
29 |
30 | /* The event group allows multiple bits for each event, but we only care about two events:
31 | * - we are connected to the AP with an IP
32 | * - we failed to connect after the maximum amount of retries */
33 | #define WIFI_CONNECTED_BIT BIT0
34 | #define WIFI_FAIL_BIT BIT1
35 |
36 | static const char *TAG = "main";
37 |
38 | static int s_retry_num = 0;
39 |
40 | static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
41 | {
42 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
43 | esp_wifi_connect();
44 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
45 | if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
46 | esp_wifi_connect();
47 | s_retry_num++;
48 | ESP_LOGI(TAG, "retry to connect to the AP");
49 | } else {
50 | xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
51 | }
52 | ESP_LOGI(TAG,"connect to the AP fail");
53 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
54 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
55 | ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
56 | s_retry_num = 0;
57 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
58 | }
59 | }
60 |
61 | void wifi_init_sta(void)
62 | {
63 | s_wifi_event_group = xEventGroupCreate();
64 |
65 | ESP_ERROR_CHECK(esp_netif_init());
66 |
67 | ESP_ERROR_CHECK(esp_event_loop_create_default());
68 | esp_netif_create_default_wifi_sta();
69 |
70 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
71 | ESP_ERROR_CHECK(esp_wifi_init(&cfg));
72 |
73 | esp_event_handler_instance_t instance_any_id;
74 | esp_event_handler_instance_t instance_got_ip;
75 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
76 | ESP_EVENT_ANY_ID,
77 | &event_handler,
78 | NULL,
79 | &instance_any_id));
80 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
81 | IP_EVENT_STA_GOT_IP,
82 | &event_handler,
83 | NULL,
84 | &instance_got_ip));
85 |
86 | wifi_config_t wifi_config = {
87 | .sta = {
88 | .ssid = CONFIG_ESP_WIFI_SSID,
89 | .password = CONFIG_ESP_WIFI_PASSWORD,
90 | /* Setting a password implies station will connect to all security modes including WEP/WPA.
91 | * However these modes are deprecated and not advisable to be used. Incase your Access point
92 | * doesn't support WPA2, these mode can be enabled by commenting below line */
93 | .threshold.authmode = WIFI_AUTH_WPA2_PSK,
94 |
95 | .pmf_cfg = {
96 | .capable = true,
97 | .required = false
98 | },
99 | },
100 | };
101 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
102 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
103 | ESP_ERROR_CHECK(esp_wifi_start() );
104 |
105 | ESP_LOGI(TAG, "wifi_init_sta finished.");
106 |
107 | /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
108 | * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
109 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
110 | WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
111 | pdFALSE,
112 | pdFALSE,
113 | portMAX_DELAY);
114 |
115 | /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
116 | * happened. */
117 | if (bits & WIFI_CONNECTED_BIT) {
118 | ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
119 | } else if (bits & WIFI_FAIL_BIT) {
120 | ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
121 | } else {
122 | ESP_LOGE(TAG, "UNEXPECTED EVENT");
123 | }
124 |
125 | /* The event will not be processed after unregister */
126 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
127 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
128 | vEventGroupDelete(s_wifi_event_group);
129 | }
130 |
131 | void initialise_mdns(void)
132 | {
133 | //initialize mDNS
134 | ESP_ERROR_CHECK( mdns_init() );
135 | //set mDNS hostname (required if you want to advertise services)
136 | ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
137 | ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
138 |
139 | //initialize service
140 | ESP_ERROR_CHECK( mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) );
141 |
142 | #if 0
143 | //set default mDNS instance name
144 | ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
145 | #endif
146 | }
147 |
148 | void client_task(void* pvParameters);
149 | void server_task(void* pvParameters);
150 |
151 | void app_main() {
152 | // Initialize NVS
153 | esp_err_t ret = nvs_flash_init();
154 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
155 | ESP_ERROR_CHECK(nvs_flash_erase());
156 | ret = nvs_flash_init();
157 | }
158 | ESP_ERROR_CHECK(ret);
159 |
160 | // Initialize WiFi
161 | wifi_init_sta();
162 |
163 | // Initialize mDNS
164 | initialise_mdns();
165 |
166 | // Create Message Buffer
167 | xMessageBufferToClient = xMessageBufferCreate(1024);
168 | configASSERT( xMessageBufferToClient );
169 |
170 | // Get the local IP address
171 | esp_netif_ip_info_t ip_info;
172 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
173 | char cparam0[64];
174 | sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
175 |
176 | // Start web socket server
177 | ws_server_start();
178 |
179 | // Start web server
180 | xTaskCreate(&server_task, "server_task", 1024*4, (void *)cparam0, 5, NULL);
181 |
182 | // Start web client
183 | xTaskCreate(&client_task, "client_task", 1024*4, NULL, 5, NULL);
184 |
185 | vTaskDelay(100);
186 | }
187 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The following five lines of boilerplate have to be in your project's
2 | # CMakeLists in this exact order for cmake to work correctly
3 | cmake_minimum_required(VERSION 3.5)
4 |
5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6 | project(web-analog)
7 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 nopnop2002
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/README.md:
--------------------------------------------------------------------------------
1 | # Vertical Linear Gauge display using Canvas Gauge
2 | 
3 |
4 | I used [this](https://canvas-gauges.com/) for gauge display.
5 | You can easily change the gauge design.
6 |
7 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/html/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ESP32 Error 404
5 |
6 |
7 |
8 |
9 |
10 |
11 | Error 404
12 | Unknown page. Return home.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/html/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nopnop2002/esp-idf-web-chart/ce073d46522b28e6a06e84bd34ece938afb5857a/VerticalLinearGauge/html/favicon.ico
--------------------------------------------------------------------------------
/VerticalLinearGauge/html/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | Your favorite style is defined here.
3 | */
4 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/html/main.js:
--------------------------------------------------------------------------------
1 | //document.getElementById("datetime").innerHTML = "WebSocket is not connected";
2 |
3 | var websocket = new WebSocket('ws://'+location.hostname+'/');
4 | var meter1 = 0;
5 | var meter2 = 0;
6 | var meter3 = 0;
7 |
8 |
9 | function sendText(name) {
10 | console.log('sendText');
11 | var data = {};
12 | data["id"] = name;
13 | console.log('data=', data);
14 | json_data = JSON.stringify(data);
15 | console.log('json_data=' + json_data);
16 | websocket.send(json_data);
17 | }
18 |
19 | websocket.onopen = function(evt) {
20 | console.log('WebSocket connection opened');
21 | var data = {};
22 | data["id"] = "init";
23 | console.log('data=', data);
24 | json_data = JSON.stringify(data);
25 | console.log('json_data=' + json_data);
26 | websocket.send(json_data);
27 | //document.getElementById("datetime").innerHTML = "WebSocket is connected!";
28 | }
29 |
30 | websocket.onmessage = function(evt) {
31 | var msg = evt.data;
32 | console.log("msg=" + msg);
33 | var values = msg.split('\4'); // \4 is EOT
34 | //console.log("values=" + values);
35 | switch(values[0]) {
36 | case 'HEAD':
37 | console.log("HEAD values[1]=" + values[1]);
38 | var h1 = document.getElementById( 'header' );
39 | h1.textContent = values[1];
40 | break;
41 |
42 | case 'METER':
43 | //console.log("gauge1=" + Object.keys(gauge1.options));
44 | //console.log("gauge1.options.units=" + gauge1.options.units);
45 | console.log("METER values[1]=" + values[1]);
46 | console.log("METER values[2]=" + values[2]);
47 | console.log("METER values[3]=" + values[3]);
48 | if (values[1] != "") {
49 | gauge1.options.units = values[1];
50 | document.getElementById("canvas1").style.display = "inline-block";
51 | meter1 = 1;
52 | }
53 | if (values[2] != "") {
54 | gauge2.options.units = values[2];
55 | document.getElementById("canvas2").style.display = "inline-block";
56 | meter2 = 1;
57 | }
58 | if (values[3] != "") {
59 | gauge3.options.units = values[3];
60 | document.getElementById("canvas3").style.display = "inline-block";
61 | meter3 = 1;
62 | }
63 | break;
64 |
65 | case 'DATA':
66 | console.log("DATA values[1]=" + values[1]);
67 | var voltage1 = parseInt(values[1], 10);
68 | gauge1.value = voltage1;
69 | gauge1.update({ valueText: values[1] });
70 | if (meter2) {
71 | console.log("DATA values[2]=" + values[2]);
72 | var voltage2 = parseInt(values[2], 10);
73 | gauge2.value = voltage2;
74 | gauge2.update({ valueText: values[2] });
75 | }
76 | if (meter3) {
77 | console.log("DATA values[3]=" + values[3]);
78 | var voltage3 = parseInt(values[3], 10);
79 | gauge3.value = voltage3;
80 | gauge3.update({ valueText: values[3] });
81 | }
82 | break;
83 |
84 | default:
85 | break;
86 | }
87 | }
88 |
89 | websocket.onclose = function(evt) {
90 | console.log('Websocket connection closed');
91 | //document.getElementById("datetime").innerHTML = "WebSocket closed";
92 | }
93 |
94 | websocket.onerror = function(evt) {
95 | console.log('Websocket error: ' + evt);
96 | //document.getElementById("datetime").innerHTML = "WebSocket error????!!!1!!";
97 | }
98 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/html/root.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Canvas Gauge
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "main.c" "web_server.c" "web_client.c"
2 | INCLUDE_DIRS "."
3 | EMBED_FILES "../html/error.html"
4 | "../html/favicon.ico"
5 | "../html/main.js"
6 | "../html/root.html"
7 | "../html/main.css")
8 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "Application configuration"
2 |
3 | config GPIO_RANGE_MIN
4 | int
5 | default 32 if IDF_TARGET_ESP32
6 | default 1 if IDF_TARGET_ESP32S2
7 | default 1 if IDF_TARGET_ESP32S3
8 | default 0 if IDF_TARGET_ESP32C2
9 | default 0 if IDF_TARGET_ESP32C3
10 | default 0 if IDF_TARGET_ESP32C6
11 |
12 | config GPIO_RANGE_MAX
13 | int
14 | default 39 if IDF_TARGET_ESP32
15 | default 10 if IDF_TARGET_ESP32S2
16 | default 10 if IDF_TARGET_ESP32S3
17 | default 4 if IDF_TARGET_ESP32C2
18 | default 4 if IDF_TARGET_ESP32C3
19 | default 6 if IDF_TARGET_ESP32C6
20 |
21 | menu "WiFi Setting"
22 |
23 | config ESP_WIFI_SSID
24 | string "WiFi SSID"
25 | default "myssid"
26 | help
27 | SSID (network name) to connect to.
28 |
29 | config ESP_WIFI_PASSWORD
30 | string "WiFi Password"
31 | default "mypassword"
32 | help
33 | WiFi password (WPA or WPA2) to connect to.
34 |
35 | config ESP_MAXIMUM_RETRY
36 | int "Maximum retry"
37 | default 5
38 | help
39 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
40 |
41 | config MDNS_HOSTNAME
42 | string "mDNS Hostname"
43 | default "esp32-server"
44 | help
45 | The mDNS host name used by the ESP32.
46 |
47 | endmenu
48 |
49 | menu "ADC Setting"
50 |
51 | config METER1_GPIO
52 | int "GPIO for ADC1"
53 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
54 | default 32 if IDF_TARGET_ESP32
55 | default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
56 | default 0 # C3 and others
57 | help
58 | ADC1_CHANNEL number.
59 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
60 | On the ESP32, 8 channels: GPIO32 - GPIO39.
61 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
62 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
63 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
64 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
65 |
66 | config ENABLE_METER2
67 | bool "Enable METER2"
68 | default n
69 | help
70 | Enable Meter2.
71 |
72 | config METER2_GPIO
73 | depends on ENABLE_METER2
74 | int "GPIO for METER2"
75 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
76 | default 33 if IDF_TARGET_ESP32
77 | default 2 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
78 | default 1 # C3 and others
79 | help
80 | ADC1_CHANNEL number.
81 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
82 | On the ESP32, 8 channels: GPIO32 - GPIO39.
83 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
84 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
85 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
86 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
87 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
88 |
89 | config ENABLE_METER3
90 | bool "Enable METER3"
91 | default n
92 | help
93 | Enable Meter3.
94 |
95 | config METER3_GPIO
96 | depends on ENABLE_METER3
97 | int "GPIO for METER3"
98 | range GPIO_RANGE_MIN GPIO_RANGE_MAX
99 | default 34 if IDF_TARGET_ESP32
100 | default 3 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
101 | default 2 # C3 and others
102 | help
103 | ADC1_CHANNEL number.
104 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to ADC.
105 | On the ESP32, 8 channels: GPIO32 - GPIO39.
106 | On the ESP32-S2, 10 channels: GPIO1 - GPIO10.
107 | On the ESP32-S3, 10 channels: GPIO1 - GPIO10.
108 | On the ESP32-C2, 5 channels: GPIO0 - GPIO4.
109 | On the ESP32-C3, 5 channels: GPIO0 - GPIO4.
110 | On the ESP32-C6, 7 channels: GPIO0 - GPIO6.
111 |
112 | config ADC_CYCLE
113 | int "ADC measurement cycle tick"
114 | range 100 1000
115 | default 100
116 | help
117 | ADC measurement cycle tick.
118 |
119 | config ENABLE_STDOUT
120 | bool "Enable STDOUT"
121 | default n
122 | help
123 | Enable STDOUT.
124 |
125 | endmenu
126 |
127 | endmenu
128 |
129 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/main/component.mk:
--------------------------------------------------------------------------------
1 | COMPONENT_EMBED_FILES := ../html/error.html
2 | COMPONENT_EMBED_FILES += ../html/favicon.ico
3 | COMPONENT_EMBED_FILES += ../html/main.js
4 | COMPONENT_EMBED_FILES += ../html/root.html
5 | COMPONENT_EMBED_FILES += ../html/bulma.css
6 | COMPONENT_EMBED_FILES += ../html/main.css
7 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/main/idf_component.yml:
--------------------------------------------------------------------------------
1 | ## IDF Component Manager Manifest File
2 | dependencies:
3 | Molorius/esp32-websocket:
4 | git: https://github.com/Molorius/esp32-websocket
5 | espressif/mdns:
6 | version: "^1.0.3"
7 | rules:
8 | - if: "idf_version >=5.0"
9 |
--------------------------------------------------------------------------------
/VerticalLinearGauge/main/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | Example using WEB Socket.
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "freertos/queue.h"
15 | #include "freertos/event_groups.h"
16 | #include "freertos/message_buffer.h"
17 |
18 | #include "esp_wifi.h"
19 | #include "esp_log.h"
20 | #include "nvs_flash.h"
21 | #include "mdns.h"
22 |
23 | #include "websocket_server.h"
24 |
25 | MessageBufferHandle_t xMessageBufferToClient;
26 |
27 | /* FreeRTOS event group to signal when we are connected*/
28 | static EventGroupHandle_t s_wifi_event_group;
29 |
30 | /* The event group allows multiple bits for each event, but we only care about two events:
31 | * - we are connected to the AP with an IP
32 | * - we failed to connect after the maximum amount of retries */
33 | #define WIFI_CONNECTED_BIT BIT0
34 | #define WIFI_FAIL_BIT BIT1
35 |
36 | static const char *TAG = "main";
37 |
38 | static int s_retry_num = 0;
39 |
40 | static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
41 | {
42 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
43 | esp_wifi_connect();
44 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
45 | if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
46 | esp_wifi_connect();
47 | s_retry_num++;
48 | ESP_LOGI(TAG, "retry to connect to the AP");
49 | } else {
50 | xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
51 | }
52 | ESP_LOGI(TAG,"connect to the AP fail");
53 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
54 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
55 | ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
56 | s_retry_num = 0;
57 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
58 | }
59 | }
60 |
61 | void wifi_init_sta(void)
62 | {
63 | s_wifi_event_group = xEventGroupCreate();
64 |
65 | ESP_ERROR_CHECK(esp_netif_init());
66 |
67 | ESP_ERROR_CHECK(esp_event_loop_create_default());
68 | esp_netif_create_default_wifi_sta();
69 |
70 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
71 | ESP_ERROR_CHECK(esp_wifi_init(&cfg));
72 |
73 | esp_event_handler_instance_t instance_any_id;
74 | esp_event_handler_instance_t instance_got_ip;
75 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
76 | ESP_EVENT_ANY_ID,
77 | &event_handler,
78 | NULL,
79 | &instance_any_id));
80 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
81 | IP_EVENT_STA_GOT_IP,
82 | &event_handler,
83 | NULL,
84 | &instance_got_ip));
85 |
86 | wifi_config_t wifi_config = {
87 | .sta = {
88 | .ssid = CONFIG_ESP_WIFI_SSID,
89 | .password = CONFIG_ESP_WIFI_PASSWORD,
90 | /* Setting a password implies station will connect to all security modes including WEP/WPA.
91 | * However these modes are deprecated and not advisable to be used. Incase your Access point
92 | * doesn't support WPA2, these mode can be enabled by commenting below line */
93 | .threshold.authmode = WIFI_AUTH_WPA2_PSK,
94 |
95 | .pmf_cfg = {
96 | .capable = true,
97 | .required = false
98 | },
99 | },
100 | };
101 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
102 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
103 | ESP_ERROR_CHECK(esp_wifi_start() );
104 |
105 | ESP_LOGI(TAG, "wifi_init_sta finished.");
106 |
107 | /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
108 | * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
109 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
110 | WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
111 | pdFALSE,
112 | pdFALSE,
113 | portMAX_DELAY);
114 |
115 | /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
116 | * happened. */
117 | if (bits & WIFI_CONNECTED_BIT) {
118 | ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
119 | } else if (bits & WIFI_FAIL_BIT) {
120 | ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
121 | } else {
122 | ESP_LOGE(TAG, "UNEXPECTED EVENT");
123 | }
124 |
125 | /* The event will not be processed after unregister */
126 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
127 | ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
128 | vEventGroupDelete(s_wifi_event_group);
129 | }
130 |
131 | void initialise_mdns(void)
132 | {
133 | //initialize mDNS
134 | ESP_ERROR_CHECK( mdns_init() );
135 | //set mDNS hostname (required if you want to advertise services)
136 | ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
137 | ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
138 |
139 | //initialize service
140 | ESP_ERROR_CHECK( mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) );
141 |
142 | #if 0
143 | //set default mDNS instance name
144 | ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
145 | #endif
146 | }
147 |
148 | void client_task(void* pvParameters);
149 | void server_task(void* pvParameters);
150 |
151 | void app_main() {
152 | // Initialize NVS
153 | esp_err_t ret = nvs_flash_init();
154 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
155 | ESP_ERROR_CHECK(nvs_flash_erase());
156 | ret = nvs_flash_init();
157 | }
158 | ESP_ERROR_CHECK(ret);
159 |
160 | // Initialize WiFi
161 | wifi_init_sta();
162 |
163 | // Initialize mDNS
164 | initialise_mdns();
165 |
166 | // Create Message Buffer
167 | xMessageBufferToClient = xMessageBufferCreate(1024);
168 | configASSERT( xMessageBufferToClient );
169 |
170 | // Get the local IP address
171 | esp_netif_ip_info_t ip_info;
172 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
173 | char cparam0[64];
174 | sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
175 |
176 | // Start web socket server
177 | ws_server_start();
178 |
179 | // Start web server
180 | xTaskCreate(&server_task, "server_task", 1024*4, (void *)cparam0, 5, NULL);
181 |
182 | // Start web client
183 | xTaskCreate(&client_task, "client_task", 1024*4, NULL, 5, NULL);
184 |
185 | vTaskDelay(100);
186 | }
187 |
--------------------------------------------------------------------------------