Last active
October 31, 2025 17:17
-
-
Save VovaStelmashchuk/7e0ef77dc14e820db6ef076451b65be8 to your computer and use it in GitHub Desktop.
ESP32 electricty tracker micro python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from machine import Pin | |
| import time | |
| import network | |
| import time | |
| import ujson as json | |
| import usocket as socket | |
| import machine | |
| import urequests | |
| led = Pin(8, Pin.OUT) | |
| led.value(0) | |
| print("Hello, ESP32-C3!") | |
| start_blick = [1024, 512, 256, 128, 64, 32, 16, 8, 4, 2] | |
| for blick in start_blick: | |
| ms = blick / 1000.0 | |
| led.value(0) | |
| time.sleep(ms) | |
| led.value(1) | |
| time.sleep(ms) | |
| CONFIG_FILE = 'config.json' | |
| AP_SSID = 'ESP32-HOTSPOT' | |
| def url_decode(s): | |
| """ | |
| A simple URL-decoding function to handle percent-encoded strings. | |
| Replaces '+' with space and '%HH' with the corresponding character. | |
| """ | |
| result = "" | |
| i = 0 | |
| while i < len(s): | |
| char = s[i] | |
| if char == '+': | |
| result += ' ' | |
| i += 1 | |
| elif char == '%': | |
| if i + 2 < len(s): | |
| try: | |
| hex_code = s[i+1:i+3] | |
| decoded_char = chr(int(hex_code, 16)) | |
| result += decoded_char | |
| i += 3 | |
| except ValueError: | |
| result += '%' | |
| i += 1 | |
| else: | |
| result += '%' | |
| i += 1 | |
| else: | |
| result += char | |
| i += 1 | |
| return result | |
| def send_data_to_network(): | |
| """ | |
| This is your main app logic | |
| It checks Wi-Fi, loads the token, and sends alive signal to the server | |
| """ | |
| if not connect_to_wifi(): | |
| print("Wi-Fi connection failed or could not be re-established. Aborting send.") | |
| return | |
| print("--- Running main application (Wi-Fi OK) ---") | |
| token = None | |
| try: | |
| with open(CONFIG_FILE, 'r') as f: | |
| config = json.load(f) | |
| token = config.get('token') | |
| except Exception as e: | |
| print(f"Could not load token from config: {e}") | |
| if not token: | |
| print("Token not found in config. Cannot send data.") | |
| return | |
| url = "https://nu31.space/api/electricty_tracker/alive" | |
| try: | |
| headers = {'Authorization': f'Bearer {token}'} | |
| response = urequests.post(url, headers=headers) | |
| print("Status Code:", response.status_code) | |
| print("Response Content:", response.text) | |
| response.close() | |
| led.value(1) | |
| time.sleep(2) | |
| led.value(0) | |
| except Exception as e: | |
| print("Error during GET request:", e) | |
| def connect_to_wifi(): | |
| """ | |
| Tries to connect to Wi-Fi using saved credentials. | |
| Returns True on success, False on failure. | |
| """ | |
| sta_if = network.WLAN(network.STA_IF) | |
| if not sta_if.isconnected(): | |
| try: | |
| with open(CONFIG_FILE, 'r') as f: | |
| config = json.load(f) | |
| ssid = config.get('ssid') | |
| password = config.get('password') | |
| if not ssid or not password: | |
| print("No saved credentials found.") | |
| return False | |
| print(f"Connecting to saved network: {ssid}...") | |
| sta_if.active(True) | |
| sta_if.connect(ssid, password) | |
| for _ in range(10): | |
| if sta_if.isconnected(): | |
| print("Connection successful!") | |
| print(f"IP Info: {sta_if.ifconfig()}") | |
| return True | |
| time.sleep(1) | |
| print("Connection failed.") | |
| sta_if.active(False) | |
| return False | |
| except OSError: | |
| print("No config file found.") | |
| return False | |
| else: | |
| return True | |
| def start_config_server(): | |
| """ | |
| Starts the Access Point and a web server to get Wi-Fi credentials and token. | |
| """ | |
| print("Starting configuration server...") | |
| sta_if = network.WLAN(network.STA_IF) | |
| sta_if.active(True) | |
| scan_results = sta_if.scan() | |
| sta_if.active(False) | |
| unique_ssids = set(net[0].decode('utf-8') for net in scan_results if net[0]) | |
| options_html = "".join(f'<option value="{ssid}">\n' for ssid in sorted(unique_ssids)) | |
| ap = network.WLAN(network.AP_IF) | |
| ap.active(True) | |
| ap.config(essid=AP_SSID) | |
| print(f"--- Connect to this Wi-Fi ---") | |
| print(f"SSID: {AP_SSID}") | |
| print(f"Then open http://{ap.ifconfig()[0]} in your browser") | |
| print("-------------------------------") | |
| html_page = f""" | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>ESP32 Wi-Fi Config</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| </head> | |
| <body style="font-family: Arial, sans-serif; text-align: center; padding: 20px;"> | |
| <h2>ESP32 Device Configuration</h2> | |
| <form action="/save" method="GET"> | |
| <p><strong>Step 1: Wi-Fi Credentials</strong></p> | |
| <p> | |
| <label for="ssid">Wi-Fi Name (SSID):</label><br> | |
| <input type="text" id="ssid" name="ssid" list="wifi-list" required | |
| style="width: 80%; padding: 10px;"> | |
| <datalist id="wifi-list"> | |
| {options_html} | |
| </datalist> | |
| </p> | |
| <p> | |
| <label for="password">Password:</label><br> | |
| <input type="password" id="password" name="password" required | |
| style="width: 80%; padding: 10px;"> | |
| </p> | |
| <p><strong>Step 2: Authorization Token</strong></p> | |
| <p> | |
| <label for="token">Your API Token:</label><br> | |
| <input type="password" id="token" name="token" required | |
| style="width: 80%; padding: 10px;"> | |
| </p> | |
| <p> | |
| <input type="submit" value="Save and Connect" | |
| style="padding: 15px 30px; background-color: #007bff; | |
| color: white; border: none; border-radius: 5px; font-size: 16px;"> | |
| </p> | |
| </form> | |
| </body> | |
| </html> | |
| """ | |
| addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] | |
| s = socket.socket() | |
| s.bind(addr) | |
| s.listen(1) | |
| while True: | |
| try: | |
| conn, addr = s.accept() | |
| print(f"Got connection from {addr}") | |
| request_line = conn.recv(1024).decode('utf-8').split('\n')[0] | |
| print(f"Request: {request_line}") | |
| if request_line.startswith('GET /save?'): | |
| try: | |
| params_str = request_line.split('?')[1].split(' ')[0] | |
| ssid = '' | |
| password = '' | |
| token = '' | |
| for part in params_str.split('&'): | |
| key_value = part.split('=', 1) | |
| if len(key_value) == 2: | |
| key = key_value[0] | |
| raw_value = key_value[1] | |
| if key == 'ssid': | |
| ssid = url_decode(raw_value) | |
| elif key == 'password': | |
| password = url_decode(raw_value) | |
| elif key == 'token': | |
| token = url_decode(raw_value) | |
| print(f"Saving SSID: {ssid}, Password: [HIDDEN], Token: [HIDDEN]") | |
| with open(CONFIG_FILE, 'w') as f: | |
| json.dump({ | |
| 'ssid': ssid, | |
| 'password': password, | |
| 'token': token | |
| }, f) | |
| conn.sendall(b'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n' | |
| b'<html><body>' | |
| b'<h1>Credentials saved!</h1>' | |
| b'<p>Rebooting to connect to your Wi-Fi...</p>' | |
| b'</body></html>') | |
| conn.close() | |
| print("Credentials saved. Rebooting...") | |
| time.sleep(2) | |
| machine.reset() | |
| except Exception as e: | |
| print(f"Error parsing save request: {e}") | |
| conn.close() | |
| elif request_line.startswith('GET /'): | |
| conn.sendall(b'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n') | |
| conn.sendall(html_page.encode('utf-8')) | |
| conn.close() | |
| except Exception as e: | |
| print(f"Web server error: {e}") | |
| if 'conn' in locals(): | |
| conn.close() | |
| # --- Main execution --- | |
| if not connect_to_wifi(): | |
| start_config_server() | |
| else: | |
| send_data_to_network() | |
| while True: | |
| print("Still connected. Sleeping for 300 seconds (5 minutes)...") | |
| time.sleep(300) | |
| send_data_to_network() | |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
IDEA: