Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,9 @@ node_modules/
__pycache__/
*.pyc


# Firmware related:
firmware/panorama/.cache/

# Runtime directory
rundir/
9 changes: 9 additions & 0 deletions firmware/panorama/.clangd
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Strip ESP32/toolchain flags that clang (x86 host) doesn't support when used for IDE diagnostics.
# Use headers from the compiler in compile_commands.json so stdlib.h and other toolchain headers are found.
CompileFlags:
BuiltinHeaders: QueryDriver
Remove:
- -mlongcalls
- -mlong-calls
- -fstrict-volatile-bitfields
- -fno-tree-switch-conversion
106 changes: 0 additions & 106 deletions firmware/panorama/src/main.cpp

This file was deleted.

127 changes: 127 additions & 0 deletions firmware/panorama/src/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#include <WiFi.h>
#include <Arduino.h>

// Wi-Fi Access Point credentials
const char* SSID = "ESP32-Interface";
const char* PASS = "12345678";
const uint16_t PORT = 9000;

// HC-SR04 pins (adjust to match your wiring)
const int TRIG_PIN = 5;
const int ECHO_PIN = 18;

WiFiServer server(PORT);
WiFiClient client;

bool sendEnabled = false;
unsigned long sampleInterval = 1000; // ms
unsigned long lastSend = 0;
unsigned long startTime = 0;

uint32_t seq = 0;
const uint16_t SENSOR_ID = 1;
const char* SENSOR_NAME = "ultrasonic_distance_cm";

// Return distance in cm, or -1.0 if no echo / timeout
float readUltrasonicCm() {
// ensure trigger is low
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);

// 10 µs HIGH pulse to trigger measurement
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);

// measure echo time (timeout 30 ms ≈ 5 m)
unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
if (duration == 0) {
return -1.0f; // no echo
}

// speed of sound ≈ 0.0343 cm/µs, divide by 2 (out and back)
float distanceCm = (duration * 0.0343f) / 2.0f;
return distanceCm;
}

void setup() {
Serial.begin(115200);

// ultrasonic sensor pins
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
digitalWrite(TRIG_PIN, LOW);

WiFi.mode(WIFI_AP);
WiFi.softAP(SSID, PASS);
IPAddress ip = WiFi.softAPIP();
Serial.printf("AP started: %s (%s)\n", SSID, ip.toString().c_str());

server.begin();
server.setNoDelay(true);
}

void handleCommand(String cmd) {
cmd.trim();
cmd.toUpperCase();

if (cmd.startsWith("START")) {
int spaceIdx = cmd.indexOf(' ');
if (spaceIdx > 0) {
float freq = cmd.substring(spaceIdx + 1).toFloat();
if (freq > 0) sampleInterval = 1000.0 / freq;
}
startTime = millis();
seq = 0; // reset sequence on start
sendEnabled = true;
Serial.printf("Signal ON, freq=%.1f Hz\n", 1000.0 / sampleInterval);

} else if (cmd.startsWith("STOP")) {
sendEnabled = false;
Serial.println("Signal OFF");

} else {
Serial.printf("Unknown cmd: %s\n", cmd.c_str());
}
}

void loop() {
// accept new client
WiFiClient newClient = server.available();
if (newClient) {
if (client && client.connected()) client.stop();
client = newClient;
client.print(F("{\"type\":\"status\",\"msg\":\"connected\"}\n"));
Serial.println("Backend connected");
}

// read commands
if (client && client.connected() && client.available()) {
String cmd = client.readStringUntil('\n');
handleCommand(cmd);
}

// send JSON data packets
if (sendEnabled && client && client.connected()) {
unsigned long now = millis();
if (now - lastSend >= sampleInterval) {
lastSend = now;

float distanceCm = readUltrasonicCm();
unsigned long timestamp = now - startTime;

String json =
"{"
"\"sensor\":\"" + String(SENSOR_NAME) + "\","
"\"sensor_id\":" + String(SENSOR_ID) + ","
"\"seq\":" + String(seq++) + ","
"\"timestamp_ms\":" + String(timestamp) + ","
"\"value\":" + String(distanceCm, 2) +
"}\n";

client.print(json);
Serial.print("Sent: ");
Serial.print(json);
}
}
}
98 changes: 98 additions & 0 deletions firmware/panorama/src/test_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import socket
import sys
import json
import threading

ESP_IP = "192.168.4.1" # ESP32 softAP IP (printed in Serial Monitor)
PORT = 9000

# Commands the ESP32 understands (sent as one line, newline-terminated):
# START [freq] - start streaming at freq Hz (default 5); e.g. "START 10"
# STOP - stop streaming
# Type QUIT or EXIT to close the connection and exit.


def read_commands(sock, stop_event):
"""Read lines from stdin and send them as commands to the ESP32."""
try:
while not stop_event.is_set():
line = sys.stdin.readline()
if not line:
break
line = line.strip()
if not line:
continue
if line.upper() in ("QUIT", "EXIT", "Q"):
stop_event.set()
break
# Send command to ESP32 (one line, newline-terminated)
try:
sock.sendall((line + "\n").encode())
print(f"[sent] {line}")
except OSError as e:
print(f"[error] send failed: {e}", file=sys.stderr)
stop_event.set()
break
except (KeyboardInterrupt, EOFError):
stop_event.set()


def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((ESP_IP, PORT))
print(f"Connected to {ESP_IP}:{PORT}")
print("Send commands: START [freq], STOP. Type QUIT to exit.\n")

# Read optional status line from ESP32
s.settimeout(0.5)
try:
status = s.recv(1024).decode().strip()
if status:
print("Status from ESP32:", status)
except socket.timeout:
pass
except OSError:
pass
s.settimeout(None)

stop_event = threading.Event()
cmd_thread = threading.Thread(target=read_commands, args=(s, stop_event), daemon=True)
cmd_thread.start()

try:
buffer = ""
while not stop_event.is_set():
try:
data = s.recv(1024)
except (OSError, socket.timeout):
continue
if not data:
print("Connection closed by ESP32")
break

buffer += data.decode(errors="replace")
while "\n" in buffer:
line, buffer = buffer.split("\n", 1)
line = line.strip()
if not line:
continue
if not line.startswith("{"):
# Status or debug line
print("ESP32:", line)
continue
try:
msg = json.loads(line)
print("JSON:", msg)
except json.JSONDecodeError:
print("Bad JSON:", line)
finally:
stop_event.set()
try:
s.sendall(b"STOP\n")
except OSError:
pass
print("Sent STOP; exiting.")


if __name__ == "__main__":
main()
Loading