# DIY IoT Implementation with ESP32
:::success
Let's Discuss with Bagas: pram.hao@gapp.nthu.edu.tw
:::
In this notespace, I will share my original journey of thinkering with IoT. I hope through this notespace, beginner (like me) can replicate and maintain any entry-level IoT project.
> Cheat sheet of internet related tech from this Giga Chad: https://mpolinowski.github.io/docs/intro
## 1. First Consideration: Communication Module and MCU
Well, this problem is relatively easy if you use off-the-shelf part like the ESP32. Why ESP32? Because it has good performance. Why does it perform well?
* Because the chip can host a WEB SERVER! and web server is requiring a lot of computational power.
* Another reason is because the built-in WiFi compability, so we can connect with the internet easily
* FreeRTOS is an open source RTOS (real-time operating system) kernel that is integrated into ESP-IDF as a component. Easy debugging! Multitasking!
* Cheap, easy to buy, a lot of variants (ESP-Cam)
* Last, the most important thing is a lot of [tutorials](https://deepbluembedded.com/esp32-eeprom-library-tutorial-arduino/) and libraries
There is also another method to connect with the internet such as Cellular Network (SIM). Mostly you will see SIM7000 or SIM7600 as the communication chips. So, what is the different here? I don't know too, So I googled it for you: https://github.com/vshymanskyy/TinyGSM/issues/595

**TLDR**: SIM7600 support GSM, better internet
Good product ref: https://www.aliexpress.com/item/4000542688096.html
You can also experiment with better chipset (Raspberry Pico, AVR, AI Chip NICLA, STM32, nRF etc) and other methods of communication such as LoRa, NB-IoT, Mesh Network, WLAN.
You can also DIY your system, but it will be so complex and take a lot of your time, especially if you want to have rapid system iteration.
*If you are interested in this topic, you can study more about **embedded system**.*
## 2. Environment Set Up
To thinker with IoT or MCU, basically you need an IDE. For most mortals, we will use Arduino IDE, but if you want try the next level you can use SDK provided by the chip manufacturer such as nRF SDK, STM SDK, and so on.
**Installing Arduino IDE**
For windows, just follow the general tutorial you can find in the google.
Better to use code example provided in each board library, check whether you can program the MCU (For example: WiFi Scanner, ChipID)
For nerd or ubuntu user :). Environment can be a little harsh to you.
For me, I cannot found the serial library. So, I try to install pyserial first for my env. But I haven't installed python yet. So, I need to install python, but should I install python or python3? I dunno! So I [googled](https://stackoverflow.com/questions/64801225/python-or-python3-what-is-the-difference) it for you.
```
sudo apt install python-is-python3
sudo apt-get install python3-serial -y
```
Second problem: the port didn't exist
```
whoami
sudo adduser <username> dialout
sudo chmod a+rw /dev/ttyUSB0
```
it worked! the port is opened now. Press the boot button while the flashed is connecting. Voila!


For the example above, I use T18_3.0 From Lilygo, set the board as ESP32-Wrover Module, as written in the chip surface.

Now, checking the WiFi scan property:

**So, congrats! Now you already succeed at confirming that you can flash the MCU and it can detect WiFi signal**
*If you use NB-IoT SIM* : https://github.com/FelixLinSY/am7020_arduino
*If you want to add external antenna: https://community.home-assistant.io/t/how-to-add-an-external-antenna-to-an-esp-board/131601/31 ufl is also a good option*
:::info
**Advance Topic: Filesystem Uploader to work with SPIFFS** *[Ref](https://randomnerdtutorials.com/install-esp32-filesystem-uploader-arduino-ide/)*
SPIFFS (Serial Peripheral Interface Flash File System) is memory management for your ESP32. More specifically, it’s memory storage that doesn’t erase after powering off your ESP32. You can use it for data logging, saving access codes, storing files, and remembering user-entered settings.
:::
## 3. Create a Network Instance
### a) Connect to a WiFi Network
Follow this great implementation of WiFi Event: https://deepbluembedded.com/esp32-connect-to-wifi-network-arduino/
*Somehow I suggest you to use 115200 baud when working with WiFi*
:::spoiler
<summary>Debug WiFi Code: </summary>
```cpp=
const char* ssid = "xxx";
const char* password = "xxx";
int WiFiStatus;
String Get_WiFiStatus(int Status){
switch(Status){
case WL_IDLE_STATUS:
return "WL_IDLE_STATUS";
case WL_SCAN_COMPLETED:
return "WL_SCAN_COMPLETED";
case WL_NO_SSID_AVAIL:
return "WL_NO_SSID_AVAIL";
case WL_CONNECT_FAILED:
return "WL_CONNECT_FAILED";
case WL_CONNECTION_LOST:
return "WL_CONNECTION_LOST";
case WL_CONNECTED:
return "WL_CONNECTED";
case WL_DISCONNECTED:
return "WL_DISCONNECTED";
}
}
void setup() {
Serial.begin(115200);
Serial.println("Connecting..");
WiFi.begin(ssid, password);
WiFiStatus = WiFi.status();
while(WiFiStatus != WL_CONNECTED){
delay(250);
WiFiStatus = WiFi.status();
Serial.println(Get_WiFiStatus(WiFiStatus));
}
Serial.println("\nConnected To The WiFi Network");
Serial.print("Local ESP32 IP: ");
Serial.println(WiFi.localIP());
}
```
:::
---
WiFi.status() return values:
* **WL_CONNECTED**: assigned when connected to a WiFi network;
* **WL_NO_SHIELD**: assigned when no WiFi shield is present;
* **WL_IDLE_STATUS**: it is a temporary status assigned when WiFi.begin() is called and remains active until the number of attempts expires (resulting in WL_CONNECT_FAILED) or a connection is established (resulting in WL_CONNECTED);
* **WL_NO_SSID_AVAIL**: assigned when no SSID are available;
* **WL_SCAN_COMPLETED**: assigned when the scan networks is completed;
* **WL_CONNECT_FAILED**: assigned when the connection fails for all the attempts;
* **WL_CONNECTION_LOST**: assigned when the connection is lost;
* **WL_DISCONNECTED**: assigned when disconnected from a network;
*Cannot connect to WiFi Network Troubleshoot:* https://techoverflow.net/2021/01/21/how-to-fix-esp32-not-connecting-to-the-wifi-network/


> You can pin restart the ESP if it won't connected to a network
> ESP.start()
**FALLBACK MECHANISM: [MULTIRUN](https://randomnerdtutorials.com/esp32-wifimulti/)**
Use this to give the MCU severals recognized/registered AP, then it will connect to the strongest RSSI
WiFiManager: config wifi wihtout hard-coding
Ref: https://dronebotworkshop.com/wifimanager/
WiFi Mode: STA(Station), AP(Access Point), SoftAP (Bridge STA+AP)
SoftAP implementation: https://techtutorialsx.com/2021/01/04/esp32-soft-ap-and-station-modes/
### b) Connect to a Cellular Network (TinyGSM)
TBD.
Interesting Prepaid SIM Card: https://www.icshop.com.tw/products/368070100227
### c) ESP-NOW: Mesh InterMCU Fast Communcation ([Ref](https://randomnerdtutorials.com/esp-now-esp32-arduino-ide/))
TBD. Back-up if I2C is not reliable
*Related implementation: https://randomnerdtutorials.com/esp8266-esp-now-wi-fi-web-server/*
## 4. Application Layer Protocol
After you are able to make sure that you have access to the MCU and the communication chip, then we can choose the suitable communication protocol
### a) Wifi & HTTP Client
**WiFi Client [Implementation](https://docs.arduino.cc/retired/library-examples/wifi-library/WiFiWebClient/)**:
```cpp=
// Creates a client that can connect to to a specified internet IP address and port
// as defined in client.connect().
WiFiClient client;
// 80 is the default port for HTTP
if (client.connect(server, 80)) {
Serial.println("connected to server");
// Make a HTTP request:
client.println("GET /search?q=arduino HTTP/1.1");
client.println("Host: www.google.com");
client.println("Connection: close");
client.println();
}
while (client.available()) {
char c = client.read();
Serial.write(c);
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting from server.");
client.stop();
// do nothing forevermore:
while (true);
}
```
**client.print()**: This method is used to send textual data. It takes various data types as arguments (like strings, integers, floats, etc.) and converts them to their textual representation before sending. It adds line breaks (\r\n) after each call unless specified otherwise.
Use **client.write()** to send raw binary data.
**HTTP Client Implementation**
Getting time free API: https://www.timeapi.io/swagger/index.html
```cpp=
HTTPClient http;
String url = "https://www.timeapi.io/api/Time/current/zone?timeZone=Asia/Singapore";
http.begin(url.c_str());
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
// Parse JSON
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print(F("$> [!] deserializeJson() failed: "));
Serial.println(error.f_str());
startTime = random(0, 1000);
} else {
String year = doc["year"];
String mon = doc["month"];
String day = doc["day"];
String hour = doc["hour"];
String mins = doc["minute"];
String value = doc["dateTime"];
startTime = year + mon + day + hour + mins;
Serial.print("$> [v] Time: ");
Serial.println(value);
}
} else {
Serial.println(F("$> [!] Error on HTTP request"));
startTime = random(0, 1000);
}
```
### b) MQTT Client
Follow this master:
* https://randomnerdtutorials.com/esp32-mqtt-publish-subscribe-arduino-ide/
* https://esp32io.com/tutorials/esp32-mqtt
We need to implement [this publish and subscribe library](https://github.com/knolleary/pubsubclient/tree/master) to connect with the MQTT broker(server) using WebSocket.
(Read More: It must run over a transport protocol that provides ordered, lossless, bi-directional connections—typically, TCP/IP.)

**Library Prereq:** [MQTT](https://github.com/256dpi/arduino-mqtt/), [ArduinoJSON](https://arduinojson.org)
**PUBLISH:**
```cpp=
StaticJsonDocument<200> message;
message["timestamp"] = millis();
message["data"] = analogRead(0); // Or you can read data from other sensors
char messageBuffer[512];
serializeJson(message, messageBuffer);
mqtt.publish(PUBLISH_TOPIC, messageBuffer);
```
> The length of the actual topic string is at most 65536 bytes. This is a limit imposed by the mqtt spec, you can't change it. It is also worth noting that the topic is encoded with utf-8, so you may have less than 65536 characters available. The payload of the message is limited to 268,435,456 bytes.
**SUBSCRIBE AND CONNECT:**
```cpp=
void connectToMQTT() {
// Connect to the MQTT broker
mqtt.begin(MQTT_BROKER_ADRRESS, MQTT_PORT, network);
// Create a handler for incoming messages
mqtt.onMessage(messageHandler);
Serial.print("ESP32 - Connecting to MQTT broker");
while (!mqtt.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
Serial.print(".");
delay(100);
}
Serial.println();
if (!mqtt.connected()) {
Serial.println("ESP32 - MQTT broker Timeout!");
return;
}
// Subscribe to a topic, the incoming messages are processed by messageHandler() function
if (mqtt.subscribe(SUBSCRIBE_TOPIC))
Serial.print("ESP32 - Subscribed to the topic: ");
else
Serial.print("ESP32 - Failed to subscribe to the topic: ");
Serial.println(SUBSCRIBE_TOPIC);
Serial.println("ESP32 - MQTT broker Connected!");
}
void messageHandler(String &topic, String &payload) {
Serial.println("ESP32 - received from MQTT:");
Serial.println("- topic: " + topic);
Serial.println("- payload:");
Serial.println(payload);
}
```
Implement **mqtt.loop()** in void loop before publish data
Here's what mqtt.loop() does:
* **Handles Incoming Messages:** It checks for any incoming messages from the MQTT broker and processes them accordingly. These messages could be commands, updates, or any other information sent from other devices or applications connected to the MQTT broker.
* **Handles Outgoing Messages:** It sends any outgoing messages that are queued for transmission to the MQTT broker. These messages could be sensor readings, status updates, or any other data that your Arduino needs to publish to other devices or applications via MQTT.
* **Maintains Connection:** It maintains the connection to the MQTT broker by handling tasks such as keep-alive pings and reconnecting if the connection is lost.
By calling mqtt.loop() in the main loop of your Arduino sketch, you ensure that MQTT communication is continuously maintained, allowing your device to send and receive messages reliably. Failure to call mqtt.loop() regularly may result in lost messages or disconnection from the MQTT broker.
### c) WebSocket
TBD. Advance method for real time multi client handling.
Ref: https://randomnerdtutorials.com/esp32-web-server-websocket-sliders/
## 5. Sensors/Peripherals, The Data Collector (Keep in mind this word: PROTOCOL)
### :electric_plug:I2C ([Ref](https://learn.adafruit.com/working-with-i2c-devices))
Designed for intrapcb communication protocol. Usually used by modern complex sensors.
**Terminology**
* SDA
* CLK
Lab: https://embedded-lab.com/blog/lab-14-inter-integrated-circuit-i2c-communication/
Typical pull-up resistor values are 4.7k Ohm for 5V devices and 2.4k Ohm for 3.3V devices.
**Cable Length**
I2C was originally designed for talking between devices separated by fairly short distances. For example, between all the chips inside an iPhone. So a total length of inches (centimeters), not feet (meters).
* *Good reference on pull-up calcultation: https://electronics.stackexchange.com/questions/461010/can-i-use-i2c-over-2m-cables*
* *Extender: https://sandboxelectronics.com/?product=active-i2c-long-cable-extender-p82b715-module*
* *Multiplexer*: https://dronebotworkshop.com/multiple-i2c-bus/
### :electric_plug: 1-wire
[Dallas](https://github.com/jmchiappa/DallasTemperature) Temp Ref: https://randomnerdtutorials.com/esp32-ds18b20-temperature-arduino-ide/
Cable length and config: https://www.analog.com/en/resources/technical-articles/guidelines-for-reliable-long-line-1wire-networks.html
:::danger
Core Problem: 'esp32_gpioMux' was not declared in this scope
Use this library instead: [OneWireNg](https://github.com/pstolarz/OneWireNg/tree/master)
:::
### :electric_plug: SPI
Common peripheral with this protocol is SD Card.
**Terminology:**
* MISO
* MOSI
* SCK
* CS
### :electric_plug: Analog Input via [ADC](https://deepbluembedded.com/esp32-adc-tutorial-read-analog-voltage-arduino/)
Bit resolution is 12 => 0 -> 4095; Voltage logic is 3.3V
## 6. Datastream & Data Logging
### a) Line Notify Test
We need to include this library: ==TridentTD_LineNotify==
Ref: https://ithelp.ithome.com.tw/articles/10271219
```cpp=
#include <WiFi.h>
#include <WiFiClient.h>
#include <TridentTD_LineNotify.h>
// Get the token for LINE Notify Webpages: Login->Create New Token->Assign Group
#define LINE_TOKEN "xxxx"
// Credential For AP
const char* ssid = "xxx";
const char* password = "xxx";
// Global Program Variables
int counter = 0;
unsigned long previousMillis = 0; // will store last temp was read
const long interval = 2000; // interval at which to read sensor
void setup(void)
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("\n\r \n\rWorking to connect");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// DEV: Time out Fall Back Reconnect to Other AP
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop(void)
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= interval) {
// DEV: Time out Fall Back Reconnect to Other AP
previousMillis = currentMillis;
counter++;
}
Serial.println(LINE.getVersion());
LINE.setToken(LINE_TOKEN);
LINE.notify("\n Counting:" + String(counter) + "!");
delay(10000);
}
```
### b) Google Script
:::info
Google app script work kinda like a serverless (lambda)
but google drive API work as end point, so you need another server to handle the upload
:::
Ref for Google Service Account (bit complicated): https://randomnerdtutorials.com/esp32-datalogging-google-sheets/
For easier method, host your web app to provide the API (GET Uplink, POST Downlink):
https://iotdesignpro.com/articles/esp32-data-logging-to-google-sheets-with-google-scripts
Web App Script [Quota & Limit](https://developers.google.com/apps-script/guides/services/quotas) = **90 mins/day**
Google Sheets API [Limit](https://developers.google.com/sheets/api/limits): 300 min/day of write
*Back-up Plan: REPL auto-ping*
:::warning
Need to find program execution time, to determine API usage
:::
**1. Create Google Sheets, get the ID**

**2. Create New Script:**

```javascript=
var sheet_id = "xxxx";
var sheet_name = "iot_data";
function doGet(e){
var now = new Date();
var ss = SpreadsheetApp.openById(sheet_id);
var sheet = ss.getSheetByName(sheet_name);
var sensor = e.parameter.sensor ? Number(e.parameter.sensor) : 0;
var date = now.toUTCString();
Logger.log("time: " + date);
sheet.appendRow([date, sensor]);
}
```
**for image base64**
:::warning
base64 increase the file size by 33%
:::
```javascript=
function doPost(e) {
try {
var parentFolderId = "13_O4T_L0WbmgLWk5RrUNbojJU2IsyiGm";
var folderName = e.parameter.folder;
var fileName = e.parameter.filename;
var mimeType = e.parameter.mimetype;
var imageData = Utilities.base64Decode(e.parameter.image);
var blob = Utilities.newBlob(imageData, mimeType, fileName);
var parentFolder = DriveApp.getFolderById(parentFolderId);
var subFolder = getOrCreateSubfolder(parentFolder, folderName);
var file = subFolder.createFile(blob);
return ContentService.createTextOutput("File Uploaded: " + file.getUrl());
} catch (error) {
return ContentService.createTextOutput("Error: " + error.message);
}
}
// Function to check if subfolder exists, otherwise create it
function getOrCreateSubfolder(parentFolder, folderName) {
var folders = parentFolder.getFoldersByName(folderName);
return folders.hasNext() ? folders.next() : parentFolder.createFolder(folderName);
}
```
**3. Deploy your web app**

**4. Test your URL API: Go to web.postman.co; insert the params**

**5. Check on the sheet**

### b) Local Web Server
References:
* REQ: https://randomnerdtutorials.com/esp32-esp8266-plot-chart-web-server/
* https://randomnerdtutorials.com/esp32-plot-readings-charts-multiple/
* PUSH: https://randomnerdtutorials.com/esp32-web-server-sent-events-sse/
**PUSH: Server-Sent Event**
> SSE allows the browser to receive automatic updates from a server via HTTP connection
Client only send get request in the first time to establish EventSource interface, and then the web server will send JSON to client if there is any new readings. The client will receive updates from the server, but it can’t send any data to the server after the initial handshake.
#### **Basic Foundation: Async Web**
**ESP32 Async Web Server ([Ref](https://randomnerdtutorials.com/esp32-async-web-server-espasyncwebserver-library/))**
The ESP32 Async Web Server is a powerful web server implementation designed specifically for the ESP32 microcontroller. It allows you to create web applications and services that can handle multiple client requests simultaneously in an asynchronous manner, meaning it can perform tasks concurrently without blocking the main execution thread.
Key features of the ESP32 Async Web Server include:
* Asynchronous Handling: It utilizes the ESP32's capabilities to handle multiple client connections concurrently without blocking, allowing for efficient handling of HTTP requests and responses.
* Event-driven Architecture: The server operates on an event-driven model, where callbacks are used to handle various stages of the HTTP request-response cycle. This architecture enables efficient resource utilization and responsiveness.
* Routing and Middleware Support: The server provides routing mechanisms to map HTTP requests to specific handler functions or resources. Additionally, middleware support allows for the insertion of custom processing logic at various stages of the request handling pipeline.
* WebSocket Support: It offers built-in support for WebSocket communication, enabling real-time bidirectional communication between the server and clients, which is useful for applications such as real-time data updates or remote control.
* Static File Serving: The server can serve static files such as HTML, CSS, JavaScript, and images directly from the ESP32's filesystem, making it suitable for hosting web applications and serving web pages.
* Authentication and Security: It supports various authentication mechanisms and provides features for securing HTTP connections using HTTPS (SSL/TLS), ensuring data confidentiality and integrity.
To construct the web server, you require two distinct files: **the Arduino sketch and the HTML file**. The HTML file must be stored within a directory named "data" within the Arduino sketch folder.
Both SPIFFS (Serial Peripheral Interface Flash File System) and SD card storage can be used to store files for an Async Web Server on an ESP (Espressif) microcontroller, such as the popular ESP8266 or ESP32. Each has its own advantages and considerations:
1. **SPIFFS:**
- **Pros:**
- It is built into the ESP8266 and ESP32 SDKs, meaning it's readily available without additional hardware.
- It resides in the flash memory of the ESP, so you don't need an external storage device.
- It's faster to access compared to SD cards due to its direct integration with the microcontroller.
- It's more robust in terms of shock and vibration, as there are no moving parts.
- **Cons:**
- Limited storage space compared to an SD card. SPIFFS storage capacity typically ranges from a few hundred kilobytes to a few megabytes, depending on the specific ESP model and the size of the flash memory.
- Limited number of write cycles. Flash memory has a finite number of write cycles, so frequent writes may degrade the flash memory over time.
2. **SD Card:**
- **Pros:**
- Offers much larger storage capacity compared to SPIFFS. SD cards are available in sizes ranging from megabytes to multiple gigabytes.
- Easily interchangeable. You can remove the SD card and replace it with another one, making it convenient for data transfer or backups.
- Longer lifespan for write operations compared to flash memory.
- **Cons:**
- Requires additional hardware in the form of an SD card module, which adds cost and complexity to the project.
- Slower access speeds compared to SPIFFS, especially when using SPI mode for communication.
- Susceptible to damage from shock and vibration due to its moving parts (the mechanical components inside the SD card).
**Conclusion:**
- If your project requires a small to moderate amount of data storage and you prioritize simplicity and cost-effectiveness, SPIFFS is a good choice.
- If you need larger storage capacity, anticipate frequent data writes, or require the flexibility of easily swapping storage media, an SD card may be a better option despite its additional hardware requirements and slower access speeds.
#### **Method: GET or POST?**
The reason GET is used here is likely because this operation is idempotent, meaning it doesn't change the state of the server. The server is expected to respond to the GET request by updating some internal state or performing some operation without altering the server's state itself. Also, GET requests are simpler and can be easily cached by browsers, which can improve performance, especially for repeated requests.
However, it's worth noting that using GET for operations that alter the server's state is generally considered a bad practice because GET requests can be cached by browsers and may be inadvertently repeated if users navigate back or refresh the page. In those cases, the more appropriate method would be POST or PUT, depending on the semantics of the operation.
GET:
* Simple to Implement: GET requests are simpler to implement because they are straightforward and typically involve retrieving data from the server.
* Caching: GET requests can be cached by browsers, which can improve performance for repeated requests to the same resource.
* Visibility: Since GET requests append data to the URL as query parameters, the data is visible in the URL. This can be advantageous for debugging and sharing links but can also pose security risks if sensitive data is included in the URL.
POST:
* Security: POST requests are more secure for sending sensitive data because the data is sent in the body of the request rather than appended to the URL.
* Complex Data: POST requests are suitable for sending complex data structures or large amounts of data since the data is sent in the request body.
* Idempotence: POST requests are considered non-idempotent, meaning that performing the same operation multiple times may result in different outcomes. This can be both an advantage and a disadvantage, depending on the use case.
In summary, GET requests are generally easier to handle for simple data retrieval operations, while POST requests offer more security and flexibility for sending complex or sensitive data. The choice between them depends on the specific requirements of your application.
#### **Architecture**

*Image above is dummy image, i will create my own if I have the time. Courtesy: unbrick.id*

To be able to save the HTML template to the **SPI File System**, please put the HTML file inside a data folder. Then use the ESP32 Sketch Data Upload in the tools section.
#### **Display (HTML)**
Resources
* Charting: https://www.highcharts.com/demo
* Modern fonts: Titilium, Josefin, Arvo, Zilla Slab, Varela Round, Nova Series
* Icon: https://fontawesome.com/search
#### Result


### c) SD Card
Ref: https://randomnerdtutorials.com/esp32-microsd-card-arduino/
Method:
1. [Test](https://lastminuteengineers.com/arduino-micro-sd-card-module-tutorial/) the module first: Use arduino Uno, select the righ CS, check if you are able to init the module and read the available file in the disk
:::warning
SD Card Module use 5V instead of 3.3V
SCK and CLK is the same
:::
### d) Blynk (Good visualization + APP, but no record)
TBD. Back-up plan
### e) ThingSpeak (Good record, bad visualization)
TBD. Back-up plan
### f) MQTT Mosquitto Broker (Advance Topics)
*Installing server:* https://mpolinowski.github.io/docs/Development/Javascript/2021-06-02--mqtt-cheat-sheet/2021-06-02/
### g) IFTTT Google Sheets (Premium)
Ref with Sleep Implementation: https://microcontrollerslab.com/esp32-esp8266-publish-sensor-readings-google-sheets-via-ifttt/
### h) Google Real Time DB Firebase
Stable solution.
## 7. Downlink and Control over the internet
### **Basic Control:**
#### a) PWM Analog Write (Duty Cycle): small to big, slow to fast
* Check the theory and how it works: https://lastminuteengineers.com/esp32-pwm-tutorial/
* Oscilloscope Demo: https://deepbluembedded.com/esp32-pwm-tutorial-examples-analogwrite-arduino/

Built-peripherals:
* **Motor Control:** https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/mcpwm.html
* **LED Control:** https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/ledc.html
> All ESP32 GPIO pins (0-15) can operate in Input or Output modes. **Except** for the pins (**34 to 39**) those are input-only pins. You just can’t drive them HIGH or LOW. They’re used only in input mode. On our board, we’ve 4 of them namely (GPIO34 – GPIO35 – GPIO36 – GPIO39). They don’t support PWM functionality as well.
> **increasing the resolution** will give you way more levels of control over the PWM’s duty cycle. Which will result in **very smooth and precise control**.
> If we set the resolution for PWM to 12 bit then you don't need to map the value
#### b) Digital Write: On or Off
TBD.
### **Downlink:**
MCU needs to check whether it receives any command/ack from a server or broker
#### a) Local WebServer Implementation
Ref: https://microcontrollerslab.com/esp32-web-server-dc-motor-speed-l298n-driver/
#### b) Blynk Implementation
TBD. Back-up plan.
#### c) MQTT Implementation
TBD. Back-up plan.
## 8. Power Supply Related Info
### Battery Shield
1 Cell Li-Ion Shield: https://www.electroschematics.com/battery-shield/
This shield contains voltage regulator, voltage boost, and also li-ion protector. The DW01-P battery protection IC is designed to protect lithium-ion/polymer battery from damage or degrading the lifetime due to overcharge, overdischarge, and/or overcurrent for one-cell lithium-ion/polymer battery powered systems, such as cellular phones.
T18 Measuring Power: https://electronics.stackexchange.com/questions/628931/how-to-measure-the-battery-voltage-in-a-ttgo-t18
### Working with voltage
TBD. Topics: Voltage Booster, Voltage Regulator
https://www.taiwansensor.com.tw/product/kis3r33s-%E5%90%8C%E6%AD%A5%E6%95%B4%E6%B5%81-dc-dc-%E9%99%8D%E5%A3%93%E9%9B%BB%E6%BA%90%E6%A8%A1%E7%B5%84-7v-24v%E8%BD%895v-3a/
### Working with logic
Many devices that accept a 5V PWM signal might still interpret a 3.3V signal as a valid logic high, especially if they are designed to be compatible with both 3.3V and 5V logic systems. However, there's no guarantee for this unless explicitly mentioned in the device's datasheet or specifications.
If the driver is tolerant to a 3.3V input signal, you can directly connect your 3.3V PWM source to it. But if it requires a 5V PWM signal, you might need a level shifter or voltage translator to convert the 3.3V signal to 5V before connecting it to the driver. These devices are designed to convert signals between different voltage levels while maintaining signal integrity and compatibility.
https://www.electronicshub.org/bidirectional-logic-level-converter/
## 9. Installation
### Cabling
* Generic temporary connector: https://www.icshop.com.tw/products/368020102098
* Modular connector 6P6C: https://www.digikey.tw/en/articles/understanding-and-specifying-modular-connectors
* Shielded Ethernet Cables (STP): protect against electromagnetic interference (EMI) and radio frequency interference (RFI).
* Power Cabling: https://fixdbebersbacher.z13.web.core.windows.net/quick-connectors-wiring.html
* Screw Terminal: https://learn.sparkfun.com/tutorials/connector-basics/temporary-connectors
* Crimp Connectors: https://www.youtube.com/watch?v=goxVeefDpQg
### Outdoor installation:

Gill Radiation & Sensor shelter
M12 Connector
### Switch Types
https://learn.sparkfun.com/tutorials/button-and-switch-basics/all
## 10. Advance Topics
### Event Timing
https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover
### Data Structures
Queue: https://github.com/SMFSW/Queue/tree/master
### Multitasking
Ref: https://www.circuitstate.com/tutorials/how-to-write-parallel-multitasking-applications-for-esp32-using-freertos-arduino/
### Prototyping
Electronic sketch: https://www.circuitlab.com/editor/#?id=7pq5wm&from=homepage
### Hosting App
https://randomnerdtutorials.com/visualize-esp32-esp8266-sensor-readings-from-anywhere/
Node Red: https://randomnerdtutorials.com/getting-started-node-red-raspberry-pi/
### Web Serial
https://randomnerdtutorials.com/esp8266-nodemcu-webserial-library/
### Introduction to RTOS
https://medium.com/@lanceharvieruntime/the-pros-and-cons-of-rtos-vs-bare-metal-which-will-you-choose-756e33ba6df7
### State Control
EEPROM: https://deepbluembedded.com/esp32-eeprom-library-tutorial-arduino/
### ModBus RTU485
https://microdigisoft.com/esp32-with-modbus-rtu-rs485-protocol-using-arduino-ide/
https://github.com/TronixLab/ModBus-RTU-Temperature-Humidity-SHT20-Sensor/tree/main
https://embeddedthere.com/how-to-interface-esp32-with-rs485-modbus-sensors-with-example-code/
Here are some common Modbus return codes defined in the library:
* **ku8MBSuccess**: The operation was successful.
* **ku8MBIllegalFunction**: The function code sent to the slave device is not supported.
* **ku8MBIllegalDataAddress**: The register address being read/written is invalid.
* **ku8MBIllegalDataValue**: The data sent in the query is invalid.
* **ku8MBSlaveDeviceFailure**: The slave device failed to process the request.
* **ku8MBResponseTimedOut**: No response was received from the slave device (timeout).