src.nth.io/

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--main/app_main.c84
-rw-r--r--main/mdns_service.c74
-rw-r--r--main/net_eth.c4
4 files changed, 107 insertions, 59 deletions
diff --git a/README.md b/README.md
index 3723596..17d346c 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,9 @@ Version: 1.0
## Overview
-Scrypted Viewport is an Ethernet-powered ambient display appliance optimized for Scrypted camera and doorbell events.
+Scrypted Viewport is an Ethernet-powered ambient display appliance optimized for Scrypted camera and doorbell
+events. It's meant to be plug and play onto a trusted POE VLAN connection with Scrypted access so there's no
+configuration done on the esp32 itself and instead is discoverd and configured within Scrypted.
Design goals:
- No Matter
diff --git a/main/app_main.c b/main/app_main.c
index 4f7a949..0897649 100644
--- a/main/app_main.c
+++ b/main/app_main.c
@@ -18,6 +18,16 @@
static const char *TAG = "viewport";
+// Log a status line for one subsystem and accumulate a one-letter flag into
+// `status` (uppercase = up, lowercase = degraded/unavailable). Lets the
+// boot log end with a single line summarizing what's actually live, so
+// running with no LAN / no panel is a self-describing degraded mode rather
+// than a panic.
+static inline void mark(esp_err_t err, char up, char *slot)
+{
+ *slot = (err == ESP_OK) ? up : (char)(up + 0x20); // 'A' -> 'a' on failure
+}
+
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
@@ -28,57 +38,63 @@ void app_main(void)
nvs_config_load(); // apply persisted config over defaults (best-effort)
ESP_LOGI(TAG, "Scrypted Viewport boot (v%s)", VIEWPORT_VERSION);
- ESP_ERROR_CHECK(net_eth_init());
- if (net_eth_wait_for_ip(30 * 1000) == ESP_OK) {
- ESP_LOGI(TAG, "online at %s", net_eth_get_ip_str());
- } else {
- ESP_LOGW(TAG, "no DHCP lease after 30s, will keep retrying in the background");
+ // ------------------------------------------------------------------
+ // Networking. Driver starts even with no cable plugged in; we just
+ // don't get a DHCP lease. mDNS + HTTP advertise / bind anyway and will
+ // start serving the moment the link comes up.
+ // ------------------------------------------------------------------
+ char flags[8] = { '-','-','-','-','-','-','-', 0 }; // E M H D J T B
+ esp_err_t eth_err = net_eth_init();
+ mark(eth_err, 'E', &flags[0]);
+
+ bool got_ip = false;
+ if (eth_err == ESP_OK) {
+ got_ip = (net_eth_wait_for_ip(15 * 1000) == ESP_OK);
+ if (got_ip) {
+ ESP_LOGI(TAG, "online at %s", net_eth_get_ip_str());
+ } else {
+ ESP_LOGW(TAG, "no DHCP lease after 15s — Ethernet driver will keep "
+ "retrying in the background; mDNS + HTTP up anyway");
+ }
}
ESP_ERROR_CHECK(state_machine_init());
ESP_ERROR_CHECK(state_client_init());
- ESP_ERROR_CHECK(mdns_service_start());
- ESP_ERROR_CHECK(http_api_start());
+ mark(mdns_service_start(), 'M', &flags[1]);
+ mark(http_api_start(), 'H', &flags[2]);
- // Display is best-effort — a missing/miswired panel must not kill
- // networking + /state.
- if (display_init() == ESP_OK) {
+ // ------------------------------------------------------------------
+ // Display + I²C-bound peripherals. Missing/miswired panel must not
+ // kill networking + /state. Failures here log a warning and continue.
+ // ------------------------------------------------------------------
+ esp_err_t dsp_err = display_init();
+ mark(dsp_err, 'D', &flags[3]);
+ if (dsp_err == ESP_OK) {
local_screens_init();
-
- // Reconcile panel with current run-state:
- // UNCONFIGURED -> IP screen (so operator can register from Scrypted)
- // ASLEEP -> backlight off (configured device booted asleep)
- // AWAKE -> leave on (not reached on fresh boot)
viewport_state_lock();
viewport_run_state_t s = viewport_state_get()->state;
viewport_state_unlock();
-
if (s == VIEWPORT_STATE_ASLEEP) {
display_sleep();
- ESP_LOGI(TAG, "display up — configured, backlight off (asleep)");
} else {
local_screens_show_ip();
- ESP_LOGI(TAG, "display up — IP screen (unconfigured)");
}
- } else {
- ESP_LOGW(TAG, "display init failed — continuing without panel");
}
- // JPEG decoder is the M5 dependency for POST /frame. Best-effort.
- if (jpeg_decoder_init() != ESP_OK) {
- ESP_LOGW(TAG, "jpeg decoder init failed — /frame will be unavailable");
- }
+ mark(jpeg_decoder_init(), 'J', &flags[4]);
- // Touch shares the panel I2C bus; only meaningful if display came up.
- if (display_is_up()) {
- if (touch_init() != ESP_OK) {
- ESP_LOGW(TAG, "touch init failed — taps won't work");
- }
+ if (dsp_err == ESP_OK) {
+ mark(touch_init(), 'T', &flags[5]);
+ } else {
+ ESP_LOGI(TAG, "touch skipped (display not up)");
}
- // BOOT button — short press = IP overlay, hold 5s = factory reset.
- // GPIO is a guess until confirmed against the Waveshare schematic.
- if (button_init() != ESP_OK) {
- ESP_LOGW(TAG, "BOOT button init failed — overlay + factory reset disabled");
- }
+ mark(button_init(), 'B', &flags[6]);
+
+ // ------------------------------------------------------------------
+ // Boot summary. Uppercase letter = subsystem live; lowercase = down.
+ // E=Ethernet M=mDNS H=HTTP D=Display J=JPEG T=Touch B=BootButton
+ // ------------------------------------------------------------------
+ ESP_LOGI(TAG, "boot complete — subsystems [%s] ip=%s",
+ flags, got_ip ? net_eth_get_ip_str() : "(no link)");
}
diff --git a/main/mdns_service.c b/main/mdns_service.c
index 761ade5..d389161 100644
--- a/main/mdns_service.c
+++ b/main/mdns_service.c
@@ -14,52 +14,82 @@ static const char *SERVICE = "_scrypted-viewport";
static const char *PROTO = "_tcp";
static const uint16_t PORT = 80;
-static esp_err_t apply_records(void)
+// Pull the current hostname + TXT values from viewport_state under the lock.
+static void snapshot_state(char *hostname, size_t host_cap,
+ const char **resolution,
+ const char **orientation,
+ char *name, size_t name_cap)
{
viewport_state_lock();
viewport_state_t *st = viewport_state_get();
- char hostname[80];
if (st->viewport_name[0]) {
- snprintf(hostname, sizeof(hostname), "viewport-%s", st->viewport_name);
+ snprintf(hostname, host_cap, "viewport-%s", st->viewport_name);
} else {
- snprintf(hostname, sizeof(hostname), "viewport");
+ snprintf(hostname, host_cap, "viewport");
}
-
- const char *resolution = viewport_state_resolution_str();
- const char *orientation = (st->orientation == VIEWPORT_ORIENTATION_PORTRAIT)
- ? "portrait" : "landscape";
- const char *name_value = st->viewport_name[0] ? st->viewport_name : "";
+ *resolution = viewport_state_resolution_str();
+ *orientation = (st->orientation == VIEWPORT_ORIENTATION_PORTRAIT)
+ ? "portrait" : "landscape";
+ snprintf(name, name_cap, "%s", st->viewport_name[0] ? st->viewport_name : "");
viewport_state_unlock();
+}
+
+static esp_err_t apply_hostname(void)
+{
+ char hostname[80];
+ const char *resolution, *orientation;
+ char name[64];
+ snapshot_state(hostname, sizeof(hostname),
+ &resolution, &orientation,
+ name, sizeof(name));
+ return mdns_hostname_set(hostname);
+}
+
+static esp_err_t apply_txt(void)
+{
+ char hostname[80];
+ const char *resolution, *orientation;
+ char name[64];
+ snapshot_state(hostname, sizeof(hostname),
+ &resolution, &orientation,
+ name, sizeof(name));
mdns_txt_item_t txt[] = {
{ "version", VIEWPORT_VERSION },
{ "resolution", resolution },
{ "orientation", orientation },
- { "name", name_value },
+ { "name", name },
};
- const size_t txt_count = sizeof(txt) / sizeof(txt[0]);
-
- ESP_RETURN_ON_ERROR(mdns_hostname_set(hostname), TAG, "hostname_set");
- ESP_RETURN_ON_ERROR(mdns_service_txt_set(SERVICE, PROTO, txt, txt_count),
- TAG, "txt_set");
-
- ESP_LOGI(TAG, "advertising %s.local on %s.%s.local:%u",
- hostname, SERVICE, PROTO, PORT);
- return ESP_OK;
+ return mdns_service_txt_set(SERVICE, PROTO, txt,
+ sizeof(txt) / sizeof(txt[0]));
}
esp_err_t mdns_service_start(void)
{
- ESP_RETURN_ON_ERROR(mdns_init(), TAG, "mdns_init");
+ // Order matters: mdns_service_add() rejects with INVALID_ARG if the
+ // hostname isn't set yet. So: init -> hostname -> service_add -> TXT.
+ ESP_RETURN_ON_ERROR(mdns_init(), TAG, "mdns_init");
+ ESP_RETURN_ON_ERROR(apply_hostname(), TAG, "hostname_set");
ESP_RETURN_ON_ERROR(
mdns_service_add(NULL, SERVICE, PROTO, PORT, NULL, 0),
TAG, "service_add");
- return apply_records();
+ ESP_RETURN_ON_ERROR(apply_txt(), TAG, "txt_set");
+
+ char hostname[80];
+ const char *resolution, *orientation;
+ char name[64];
+ snapshot_state(hostname, sizeof(hostname),
+ &resolution, &orientation,
+ name, sizeof(name));
+ ESP_LOGI(TAG, "mDNS up — %s.local advertising %s.%s.local on :%u",
+ hostname, SERVICE, PROTO, PORT);
+ return ESP_OK;
}
esp_err_t mdns_service_refresh(void)
{
- return apply_records();
+ ESP_RETURN_ON_ERROR(apply_hostname(), TAG, "hostname_set");
+ return apply_txt();
}
diff --git a/main/net_eth.c b/main/net_eth.c
index 640d880..f4dad8f 100644
--- a/main/net_eth.c
+++ b/main/net_eth.c
@@ -24,8 +24,8 @@
#define PIN_PHY_TXD0 34
#define PIN_PHY_TXD1 35
#define PIN_PHY_CRS_DV 28
-#define PIN_PHY_RXD0 30
-#define PIN_PHY_RXD1 29
+#define PIN_PHY_RXD0 29
+#define PIN_PHY_RXD1 30
#define PIN_PHY_RESET 51
#define PHY_ADDR 1