first commit

This commit is contained in:
Jon
2026-04-12 22:26:16 +01:00
commit 5d3b0caf93
5 changed files with 1026 additions and 0 deletions

42
app.overlay Normal file
View File

@@ -0,0 +1,42 @@
/ {
chosen {
zephyr,console = &cdc_acm_uart0;
zephyr,shell-uart = &cdc_acm_uart0;
};
};
&zephyr_udc0 {
cdc_acm_uart0: cdc_acm_uart0 {
compatible = "zephyr,cdc-acm-uart";
};
};
&flash0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
/* Reserve last 64KB for settings storage */
storage_partition: partition@3f0000 {
label = "storage";
reg = <0x003f0000 0x00010000>;
};
};
};
/ {
aliases {
sw0 = &door_sensor;
};
gpio_keys {
compatible = "gpio-keys";
door_sensor: door_sensor {
gpios = <&gpio0 22 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
label = "Door Reed Switch";
};
};
};

163
prj.conf Normal file
View File

@@ -0,0 +1,163 @@
CONFIG_NETWORKING=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_TCP=y
CONFIG_NET_LOG=y
CONFIG_NET_IPV6_RA_RDNSS=y
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2
CONFIG_PRINTK=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_POSIX_API=y
# Enable IPv6 support
CONFIG_NET_IPV6=n
# Enable IPv4 support
CONFIG_NET_IPV4=y
# Enable the MQTT Lib
CONFIG_MQTT_LIB=y
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1"
CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2"
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.178.109"
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.168.178.40"
CONFIG_MAIN_STACK_SIZE=2048
# For IPv6
CONFIG_NET_BUF_DATA_SIZE=256
CONFIG_NET_SHELL=y
CONFIG_ENTROPY_GENERATOR=y
CONFIG_TEST_RANDOM_GENERATOR=y
# Enable settings subsystem for persistent storage
CONFIG_SETTINGS=y
CONFIG_SETTINGS_RUNTIME=y
CONFIG_NVS=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y
# Enable WiFi credentials storage
CONFIG_WIFI_CREDENTIALS=y
CONFIG_WIFI_CREDENTIALS_BACKEND_SETTINGS=y
###################
CONFIG_EARLY_CONSOLE=y
CONFIG_NETWORKING=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_MAIN_STACK_SIZE=5200
CONFIG_SHELL_STACK_SIZE=5200
CONFIG_NET_TX_STACK_SIZE=2048
CONFIG_NET_RX_STACK_SIZE=2048
CONFIG_NET_PKT_RX_COUNT=10
CONFIG_NET_PKT_TX_COUNT=10
CONFIG_NET_BUF_RX_COUNT=20
CONFIG_NET_BUF_TX_COUNT=20
CONFIG_NET_MAX_CONTEXTS=10
CONFIG_NET_DHCPV4=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=n
CONFIG_NET_TCP=y
CONFIG_NET_LOG=y
CONFIG_INIT_STACKS=y
CONFIG_NET_SHELL=y
CONFIG_NET_STATISTICS=y
CONFIG_NET_STATISTICS_PERIODIC_OUTPUT=n
CONFIG_WIFI=y
CONFIG_WIFI_LOG_LEVEL_ERR=y
CONFIG_NET_L2_WIFI_SHELL=y
# printing of scan results puts pressure on queues in new locking
# design in net_mgmt. So, use a higher timeout for a crowded
# environment.
CONFIG_NET_MGMT_EVENT_QUEUE_TIMEOUT=5000
CONFIG_NET_MGMT_EVENT_QUEUE_SIZE=16
# Enable USB CDC ACM for console
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_CDC_ACM=y
CONFIG_UART_LINE_CTRL=y
# Use USB for console instead of UART
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y
CONFIG_SHELL_BACKEND_SERIAL_CHECK_DTR=y
#CONFIG_UART_CONSOLE_ON_DEV_NAME="CDC_ACM_0"
#CONFIG_WIFI_INFINEON_AIROC=y
CONFIG_NET_L2_WIFI_MGMT=y
# Enable settings subsystem for persistent storage
CONFIG_SETTINGS=y
CONFIG_SETTINGS_RUNTIME=y
CONFIG_NVS=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y
# Enable WiFi credentials storage
CONFIG_WIFI_CREDENTIALS=y
CONFIG_WIFI_CREDENTIALS_BACKEND_SETTINGS=y
# Optional: Auto-connect on boot
CONFIG_NET_CONFIG_AUTO_INIT=y
CONFIG_NET_CONFIG_NEED_IPV4=y
# MPU settings for flash access
CONFIG_MPU_ALLOW_FLASH_WRITE=y
# Auto-connect to saved WiFi on boot
#CONFIG_NET_CONNECTION_MANAGER=y
#CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=1024
#CONFIG_NET_MGMT_EVENT_STACK_SIZE=1024
# WEBSOCKETS
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
# Networking HTTP POST
#CONFIG_NET_SOCKETS=y
#CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_NET_TCP=y
#CONFIG_NET_HTTP_CLIENT=y
CONFIG_DNS_RESOLVER=y
CONFIG_NET_DHCPV4=y
CONFIG_HTTP_CLIENT=y
# Shell (if you want to keep the shell)
#CONFIG_SHELL=y
#CONFIG_SHELL_BACKEND_SERIAL=y
# USB CDC
#CONFIG_USB_DEVICE_STACK=y
#CONFIG_USB_CDC_ACM=y
#CONFIG_UART_LINE_CTRL=y
#CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y
# buttons
CONFIG_GPIO=y
CONFIG_USB_DEVICE_PRODUCT="Pico Zephyr Device"
CONFIG_USB_DEVICE_PID=0x0001
CONFIG_USB_DEVICE_VID=0x2FE3
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y

67
src/config.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __CONFIG_H__
#define __CONFIG_H__
#ifdef CONFIG_NET_CONFIG_SETTINGS
#ifdef CONFIG_NET_IPV6
#define ZEPHYR_ADDR CONFIG_NET_CONFIG_MY_IPV6_ADDR
#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV6_ADDR
#else
#define ZEPHYR_ADDR CONFIG_NET_CONFIG_MY_IPV4_ADDR
#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV4_ADDR
#endif
#else
#ifdef CONFIG_NET_IPV6
#define ZEPHYR_ADDR "2001:db8::1"
#define SERVER_ADDR "2001:db8::2"
#else
#define ZEPHYR_ADDR "192.168.178.109"
#define SERVER_ADDR "192.168.1.40"
#endif
#endif
#if defined(CONFIG_SOCKS)
#define SOCKS5_PROXY_ADDR SERVER_ADDR
#define SOCKS5_PROXY_PORT 1080
#endif
#ifdef CONFIG_MQTT_LIB_TLS
#ifdef CONFIG_MQTT_LIB_WEBSOCKET
#define SERVER_PORT 9001
#else
#define SERVER_PORT 8883
#endif /* CONFIG_MQTT_LIB_WEBSOCKET */
#else
#ifdef CONFIG_MQTT_LIB_WEBSOCKET
#define SERVER_PORT 9001
#else
#define SERVER_PORT 1883
#endif /* CONFIG_MQTT_LIB_WEBSOCKET */
#endif
#define APP_CONNECT_TIMEOUT_MS 2000
#define APP_SLEEP_MSECS 500
#define APP_CONNECT_TRIES 10
#define APP_MQTT_BUFFER_SIZE 128
#define MQTT_CLIENTID "zephyr_publisher"
/* Set the following to 1 to enable the Bluemix topic format */
#define APP_BLUEMIX_TOPIC 0
/* These are the parameters for the Bluemix topic format */
#if APP_BLUEMIX_TOPIC
#define BLUEMIX_DEVTYPE "sensor"
#define BLUEMIX_DEVID "carbon"
#define BLUEMIX_EVENT "status"
#define BLUEMIX_FORMAT "json"
#endif
#endif

609
src/main.c Normal file
View File

@@ -0,0 +1,609 @@
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/mqtt.h>
#include <zephyr/net/wifi_credentials.h>
#include <zephyr/net/wifi_mgmt.h>
#include <zephyr/net/net_mgmt.h>
#include <zephyr/net/net_if.h>
#include <zephyr/random/random.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/printk.h>
#include <string.h>
#include <inttypes.h>
LOG_MODULE_REGISTER(door_sensor, LOG_LEVEL_INF);
/* ========== Configuration ========== */
#define MQTT_BROKER_ADDR "78.141.235.43"
#define MQTT_BROKER_PORT 1883
#define MQTT_CLIENT_ID "pico2w_sensor"
#define MQTT_TOPIC_STATUS "sensors/motion"
#define MQTT_TOPIC_ALERT "alert"
// Power-saving configuration
#define STATUS_INTERVAL_MS (600000) // Send status every 600 seconds
#define WIFI_TIMEOUT_MS (10000) // WiFi connection timeout
#define MQTT_TIMEOUT_MS (5000) // MQTT connection timeout
#define CONNECTION_KEEP_ALIVE_MS (500) // REDUCED: Keep connection for batching
#define MAX_RETRY_ATTEMPTS 3
// Debounce configuration
#define DEBOUNCE_DELAY_MS (50) // Debounce time
#define EVENT_QUEUE_SIZE 10 // Queue for events
/* ========== Door Sensor GPIO ========== */
#define SW0_NODE DT_ALIAS(sw0)
#if !DT_NODE_HAS_STATUS_OKAY(SW0_NODE)
#error "Unsupported board: sw0 devicetree alias is not defined"
#endif
static const struct gpio_dt_spec door_sensor = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0});
static struct gpio_callback door_cb_data;
/* ========== WiFi Credentials ========== */
struct wifi_credentials_personal creds = {
.header = {
.ssid = "fuck off",
.ssid_len = 8,
.type = WIFI_SECURITY_TYPE_PSK,
},
.password = "09701067356094858066",
.password_len = 20,
};
/* ========== MQTT Buffers and Context ========== */
static uint8_t rx_buffer[256];
static uint8_t tx_buffer[256];
static struct mqtt_client client;
static struct sockaddr_storage broker;
static struct pollfd fds;
/* ========== Event Queue Structure ========== */
struct door_event {
bool door_open;
int64_t timestamp;
};
static struct {
struct door_event events[EVENT_QUEUE_SIZE];
size_t head;
size_t tail;
size_t count;
struct k_mutex mutex;
} event_queue;
/* ========== State Management ========== */
static struct {
bool wifi_connected;
bool mqtt_connected;
bool door_open;
int64_t last_door_change;
int64_t last_status_time;
char device_serial[32];
} state = {0};
/* ========== Debounce Work ========== */
static struct k_work_delayable debounce_work;
/* ========== Event Queue Functions ========== */
static void event_queue_init(void)
{
k_mutex_init(&event_queue.mutex);
event_queue.head = 0;
event_queue.tail = 0;
event_queue.count = 0;
}
static bool event_queue_push(bool door_open, int64_t timestamp)
{
k_mutex_lock(&event_queue.mutex, K_FOREVER);
if (event_queue.count >= EVENT_QUEUE_SIZE) {
LOG_WRN("Event queue full, dropping oldest event");
event_queue.tail = (event_queue.tail + 1) % EVENT_QUEUE_SIZE;
event_queue.count--;
}
event_queue.events[event_queue.head].door_open = door_open;
event_queue.events[event_queue.head].timestamp = timestamp;
event_queue.head = (event_queue.head + 1) % EVENT_QUEUE_SIZE;
event_queue.count++;
k_mutex_unlock(&event_queue.mutex);
return true;
}
static bool event_queue_pop(struct door_event *event)
{
k_mutex_lock(&event_queue.mutex, K_FOREVER);
if (event_queue.count == 0) {
k_mutex_unlock(&event_queue.mutex);
return false;
}
*event = event_queue.events[event_queue.tail];
event_queue.tail = (event_queue.tail + 1) % EVENT_QUEUE_SIZE;
event_queue.count--;
k_mutex_unlock(&event_queue.mutex);
return true;
}
static size_t event_queue_size(void)
{
size_t count;
k_mutex_lock(&event_queue.mutex, K_FOREVER);
count = event_queue.count;
k_mutex_unlock(&event_queue.mutex);
return count;
}
/* ========== WiFi Event Callback ========== */
static struct net_mgmt_event_callback wifi_mgmt_cb;
static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
uint64_t mgmt_event, struct net_if *iface)
{
switch (mgmt_event) {
case NET_EVENT_WIFI_CONNECT_RESULT:
LOG_INF("WiFi connected");
state.wifi_connected = true;
break;
case NET_EVENT_WIFI_DISCONNECT_RESULT:
LOG_INF("WiFi disconnected");
state.wifi_connected = false;
state.mqtt_connected = false;
break;
default:
break;
}
}
/* ========== Device Serial/ID ========== */
static void get_device_serial(char *serial_buf, size_t len)
{
uint32_t id = sys_rand32_get();
snprintf(serial_buf, len, "PICO2W_%08X", id);
}
/* ========== MQTT Event Handler ========== */
void mqtt_evt_handler(struct mqtt_client *const cli, const struct mqtt_evt *evt)
{
switch (evt->type) {
case MQTT_EVT_CONNACK:
if (evt->result == 0) {
state.mqtt_connected = true;
LOG_INF("MQTT connected!");
} else {
LOG_ERR("MQTT connection failed: %d", evt->result);
state.mqtt_connected = false;
}
break;
case MQTT_EVT_DISCONNECT:
LOG_DBG("MQTT disconnected");
state.mqtt_connected = false;
break;
case MQTT_EVT_PUBACK:
LOG_DBG("Message published (ID: %u)", evt->param.puback.message_id);
break;
default:
break;
}
}
/* ========== Debounce Work Handler ========== */
static void debounce_work_fn(struct k_work *work)
{
int current_state = gpio_pin_get_dt(&door_sensor);
bool door_is_open = (current_state == 1);
// Only queue if state actually changed
if (door_is_open != state.door_open) {
state.door_open = door_is_open;
state.last_door_change = k_uptime_get();
event_queue_push(door_is_open, state.last_door_change);
LOG_INF("Door %s (debounced) - queued for sending",
door_is_open ? "OPENED" : "CLOSED");
}
}
/* ========== Door Sensor Interrupt ========== */
void door_state_changed_handler(const struct device *dev, struct gpio_callback *cb,
uint32_t pins)
{
// Reschedule debounce - resets timer on each interrupt
k_work_reschedule(&debounce_work, K_MSEC(DEBOUNCE_DELAY_MS));
}
/* ========== WiFi Connection Management ========== */
static int wifi_connect(void)
{
int ret;
struct net_if *iface;
if (state.wifi_connected) {
LOG_DBG("WiFi already connected");
return 0;
}
LOG_INF("Connecting to WiFi...");
net_mgmt_init_event_callback(&wifi_mgmt_cb, wifi_mgmt_event_handler,
NET_EVENT_WIFI_CONNECT_RESULT |
NET_EVENT_WIFI_DISCONNECT_RESULT);
net_mgmt_add_event_callback(&wifi_mgmt_cb);
ret = wifi_credentials_set_personal_struct(&creds);
if (ret < 0) {
LOG_ERR("Failed to store WiFi credentials: %d", ret);
return ret;
}
iface = net_if_get_default();
if (!iface) {
LOG_ERR("No network interface found");
return -ENODEV;
}
ret = net_mgmt(NET_REQUEST_WIFI_CONNECT_STORED, iface, NULL, 0);
if (ret < 0 && ret != -EALREADY) {
LOG_ERR("WiFi connection request failed: %d", ret);
return ret;
}
int64_t timeout = k_uptime_get() + WIFI_TIMEOUT_MS;
while (!state.wifi_connected && k_uptime_get() < timeout) {
k_sleep(K_MSEC(100));
}
if (!state.wifi_connected) {
LOG_ERR("WiFi connection timeout");
return -ETIMEDOUT;
}
k_sleep(K_MSEC(1000));
LOG_INF("WiFi connected successfully");
return 0;
}
static void wifi_disconnect(void)
{
struct net_if *iface;
if (!state.wifi_connected) {
return;
}
LOG_INF("Disconnecting WiFi...");
iface = net_if_get_default();
if (iface) {
net_mgmt(NET_REQUEST_WIFI_DISCONNECT, iface, NULL, 0);
}
state.wifi_connected = false;
state.mqtt_connected = false;
}
/* ========== MQTT Connection Management ========== */
static void mqtt_setup(void)
{
struct sockaddr_in *broker4 = (struct sockaddr_in *)&broker;
mqtt_client_init(&client);
broker4->sin_family = AF_INET;
broker4->sin_port = htons(MQTT_BROKER_PORT);
zsock_inet_pton(AF_INET, MQTT_BROKER_ADDR, &broker4->sin_addr);
client.broker = &broker;
client.evt_cb = mqtt_evt_handler;
client.client_id.utf8 = (uint8_t *)MQTT_CLIENT_ID;
client.client_id.size = strlen(MQTT_CLIENT_ID);
client.password = NULL;
client.user_name = NULL;
client.protocol_version = MQTT_VERSION_3_1_1;
client.rx_buf = rx_buffer;
client.rx_buf_size = sizeof(rx_buffer);
client.tx_buf = tx_buffer;
client.tx_buf_size = sizeof(tx_buffer);
client.transport.type = MQTT_TRANSPORT_NON_SECURE;
}
static int mqtt_connect_broker(void)
{
int rc;
if (state.mqtt_connected) {
LOG_DBG("MQTT already connected");
return 0;
}
LOG_INF("Connecting to MQTT broker...");
mqtt_setup();
rc = mqtt_connect(&client);
if (rc != 0) {
LOG_ERR("MQTT connect failed: %d", rc);
return rc;
}
fds.fd = client.transport.tcp.sock;
fds.events = POLLIN;
int64_t timeout = k_uptime_get() + MQTT_TIMEOUT_MS;
while (!state.mqtt_connected && k_uptime_get() < timeout) {
if (poll(&fds, 1, 100) > 0) {
mqtt_input(&client);
}
mqtt_live(&client);
}
if (!state.mqtt_connected) {
LOG_ERR("MQTT connection timeout");
mqtt_abort(&client);
return -ETIMEDOUT;
}
LOG_INF("MQTT connected successfully");
return 0;
}
static void mqtt_disconnect_broker(void)
{
if (!state.mqtt_connected) {
return;
}
LOG_DBG("Disconnecting from MQTT broker...");
mqtt_disconnect(&client, NULL);
state.mqtt_connected = false;
}
/* ========== MQTT Publish ========== */
static int mqtt_publish_to_topic(const char *topic, const char *message)
{
struct mqtt_publish_param param;
if (!state.mqtt_connected) {
LOG_ERR("Cannot publish - MQTT not connected");
return -ENOTCONN;
}
param.message.topic.qos = MQTT_QOS_0_AT_MOST_ONCE;
param.message.topic.topic.utf8 = (uint8_t *)topic;
param.message.topic.topic.size = strlen(topic);
param.message.payload.data = (uint8_t *)message;
param.message.payload.len = strlen(message);
param.message_id = sys_rand32_get();
param.dup_flag = 0;
param.retain_flag = 0;
int rc = mqtt_publish(&client, &param);
if (rc == 0) {
for (int i = 0; i < 5; i++) {
if (poll(&fds, 1, 100) > 0) {
mqtt_input(&client);
}
mqtt_live(&client);
}
}
return rc;
}
/* ========== Connection Handler with Retry ========== */
#define MAX_WIFI_RETRIES 3
#define MAX_MQTT_RETRIES 3
static int ensure_connection(void)
{
int wifi_attempts = 0;
int mqtt_attempts = 0;
int ret;
while (wifi_attempts < MAX_WIFI_RETRIES) {
// (Re)connect WiFi
ret = wifi_connect();
if (ret != 0) {
LOG_WRN("WiFi connection failed (attempt %d/%d)",
wifi_attempts + 1, MAX_WIFI_RETRIES);
wifi_disconnect();
wifi_attempts++;
k_sleep(K_SECONDS(3));
continue; // Try WiFi again
}
// WiFi connected; now try MQTT up to 3 times
mqtt_attempts = 0;
while (mqtt_attempts < MAX_MQTT_RETRIES) {
ret = mqtt_connect_broker();
if (ret == 0) {
// Success!
return 0;
}
LOG_WRN("MQTT connection failed (attempt %d/%d)",
mqtt_attempts + 1, MAX_MQTT_RETRIES);
mqtt_disconnect_broker();
mqtt_attempts++;
k_sleep(K_SECONDS(2));
}
// MQTT could not connect after MAX_MQTT_RETRIES - restart WiFi
LOG_ERR("MQTT repeatedly failed after WiFi was attached; restarting WiFi...");
wifi_disconnect();
wifi_attempts++;
k_sleep(K_SECONDS(4));
}
LOG_ERR("Failed to establish WiFi/MQTT connection after all retries");
return -EFAULT;
}
/* ========== Process ALL Queued Events ========== */
static int process_all_events(void)
{
int ret;
char message[128];
struct door_event event;
int events_sent = 0;
// Ensure we're connected first
ret = ensure_connection();
if (ret != 0) {
return ret;
}
// Send all queued events
while (event_queue_pop(&event)) {
snprintf(message, sizeof(message),
"{\"serial\":\"%s\",\"event\":\"door_%s\",\"timestamp\":%lld}",
state.device_serial,
event.door_open ? "opened" : "closed",
event.timestamp);
ret = mqtt_publish_to_topic(MQTT_TOPIC_ALERT, message);
if (ret == 0) {
LOG_INF("Event sent: door %s", event.door_open ? "opened" : "closed");
events_sent++;
} else {
LOG_ERR("Failed to send event: %d", ret);
// Re-queue failed event
event_queue_push(event.door_open, event.timestamp);
break;
}
// Small delay between messages
k_sleep(K_MSEC(100));
}
// Keep connection alive briefly in case more events arrive
k_sleep(K_MSEC(CONNECTION_KEEP_ALIVE_MS));
// Disconnect to save power
mqtt_disconnect_broker();
wifi_disconnect();
LOG_INF("Sent %d event(s), %d remaining in queue",
events_sent, event_queue_size());
return 0;
}
/* ========== Door Sensor Initialization ========== */
static int init_door_sensor(void)
{
int ret;
if (!gpio_is_ready_dt(&door_sensor)) {
LOG_ERR("Door sensor device %s is not ready", door_sensor.port->name);
return -ENODEV;
}
ret = gpio_pin_configure_dt(&door_sensor, GPIO_INPUT);
if (ret != 0) {
LOG_ERR("Failed to configure door sensor pin: %d", ret);
return ret;
}
ret = gpio_pin_interrupt_configure_dt(&door_sensor, GPIO_INT_EDGE_BOTH);
if (ret != 0) {
LOG_ERR("Failed to configure interrupt: %d", ret);
return ret;
}
gpio_init_callback(&door_cb_data, door_state_changed_handler, BIT(door_sensor.pin));
gpio_add_callback(door_sensor.port, &door_cb_data);
// Initialize debounce work
k_work_init_delayable(&debounce_work, debounce_work_fn);
// Read initial state
state.door_open = (gpio_pin_get_dt(&door_sensor) == 1);
LOG_INF("Door sensor initialized (initial state: %s)",
state.door_open ? "OPEN" : "CLOSED");
return 0;
}
/* ========== Main Application ========== */
int main(void)
{
int ret;
char message[128];
LOG_INF("Power-optimized door sensor with debouncing starting...");
// Initialize event queue
event_queue_init();
// Get device serial/ID
get_device_serial(state.device_serial, sizeof(state.device_serial));
LOG_INF("Device ID: %s", state.device_serial);
// Initialize door sensor
ret = init_door_sensor();
if (ret < 0) {
LOG_ERR("Door sensor initialization failed: %d", ret);
return ret;
}
state.last_status_time = k_uptime_get();
LOG_INF("System ready - entering low-power monitoring mode");
while (1) {
int64_t now = k_uptime_get();
/* Process ALL queued door events */
if (event_queue_size() > 0) {
LOG_INF("Processing %d queued event(s)...", event_queue_size());
ret = process_all_events();
if (ret != 0) {
LOG_ERR("Failed to process events: %d", ret);
}
state.last_status_time = now; // Reset status timer after events
}
/* Handle periodic status update */
if ((now - state.last_status_time) >= STATUS_INTERVAL_MS) {
LOG_INF("Sending periodic status update...");
ret = ensure_connection();
if (ret == 0) {
int uptime_sec = (int)(now / 1000);
snprintf(message, sizeof(message),
"{\"serial\":\"%s\",\"uptime\":%d,\"door\":\"%s\"}",
state.device_serial,
uptime_sec,
state.door_open ? "open" : "closed");
ret = mqtt_publish_to_topic(MQTT_TOPIC_STATUS, message);
k_sleep(K_MSEC(500));
mqtt_disconnect_broker();
wifi_disconnect();
if (ret == 0) {
LOG_INF("Status update sent");
}
}
state.last_status_time = now;
}
k_sleep(K_MSEC(100));
}
return 0;
}

145
src/test_certs.h Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __TEST_CERTS_H__
#define __TEST_CERTS_H__
#if defined(CONFIG_NET_SOCKETS_OFFLOAD)
/* By default only certificates in DER format are supported. If you want to use
* certificate in PEM format, you can enable support for it in Kconfig.
*/
#if defined(CONFIG_TLS_CREDENTIAL_FILENAMES)
static const unsigned char ca_certificate[] = "ca_cert.der";
#else
static const unsigned char ca_certificate[] = {
#include "ca_cert.der.inc"
};
#endif
#else
#include <mbedtls/ssl_ciphersuites.h>
#if defined(MBEDTLS_X509_CRT_PARSE_C)
/* This byte array can be generated by
* "cat ca.crt | sed -e '1d;$d' | base64 -d |xxd -i"
*/
static const unsigned char ca_certificate[] = {
0x30, 0x82, 0x02, 0xfb, 0x30, 0x82, 0x01, 0xe3,
0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
0xee, 0x10, 0x1f, 0xc1, 0xf2, 0x30, 0xe9, 0x11,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
0x04, 0x03, 0x0c, 0x09, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x68, 0x6f, 0x73, 0x74, 0x30, 0x1e, 0x17,
0x0d, 0x31, 0x37, 0x30, 0x36, 0x32, 0x36, 0x31,
0x30, 0x35, 0x36, 0x31, 0x30, 0x5a, 0x17, 0x0d,
0x34, 0x34, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30,
0x35, 0x36, 0x31, 0x30, 0x5a, 0x30, 0x14, 0x31,
0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68,
0x6f, 0x73, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
0x82, 0x01, 0x01, 0x00, 0xc6, 0x00, 0x7b, 0x0d,
0xd1, 0x17, 0x43, 0x6b, 0xa9, 0xa7, 0x79, 0x9c,
0x0f, 0x8d, 0x77, 0x91, 0xd2, 0xf7, 0x47, 0x35,
0xb3, 0x17, 0xe2, 0xdd, 0xed, 0x6d, 0x01, 0xf9,
0xb1, 0x92, 0xc9, 0x48, 0x80, 0xe0, 0x1f, 0xcf,
0xb7, 0xa4, 0x5f, 0xf0, 0x36, 0xea, 0xbf, 0xe1,
0x33, 0xf8, 0xa9, 0xc5, 0xe6, 0xd4, 0x19, 0x8b,
0x82, 0x25, 0xd9, 0x19, 0x74, 0x70, 0x79, 0xec,
0xc6, 0x68, 0xc9, 0xef, 0xce, 0x1a, 0xa9, 0xf0,
0xb7, 0x01, 0x35, 0x91, 0xff, 0xd3, 0x75, 0x6e,
0x02, 0xba, 0x06, 0x9a, 0x2a, 0xac, 0xcf, 0x22,
0xbf, 0x2b, 0x1f, 0xc1, 0x72, 0x38, 0x22, 0x35,
0xea, 0xda, 0x6f, 0xdd, 0x67, 0xa2, 0x2b, 0x19,
0x38, 0x19, 0x0e, 0x44, 0xd1, 0x71, 0x38, 0xb4,
0x6d, 0x26, 0x85, 0xd6, 0xc6, 0xbe, 0xc1, 0x6f,
0x3c, 0xee, 0xaf, 0x94, 0x3c, 0x05, 0x56, 0x4e,
0xad, 0x53, 0x81, 0x8b, 0xd4, 0x23, 0x31, 0x69,
0x72, 0x27, 0x93, 0xb4, 0x3a, 0xac, 0x23, 0xe8,
0x10, 0xae, 0xf5, 0x9f, 0x0b, 0xa6, 0x6e, 0xd3,
0x73, 0xca, 0x18, 0x11, 0xca, 0xbe, 0x71, 0x00,
0x56, 0x29, 0x34, 0x54, 0xcc, 0xda, 0x29, 0x5b,
0x26, 0x29, 0x99, 0x4d, 0x5f, 0xa1, 0xa6, 0xb9,
0xcb, 0x2b, 0xb2, 0x0f, 0x10, 0x00, 0x04, 0xa9,
0x11, 0x2c, 0x48, 0xb1, 0x99, 0xa5, 0xca, 0x7c,
0x67, 0xa5, 0xbe, 0x14, 0x20, 0x12, 0xb7, 0x3b,
0x7a, 0x4f, 0xdc, 0xc7, 0xd5, 0x2d, 0x04, 0x66,
0xbb, 0xf5, 0x0c, 0xcd, 0xf1, 0x32, 0x39, 0xd7,
0x51, 0x9b, 0xba, 0xdb, 0xf1, 0xa7, 0xfe, 0x2d,
0x9a, 0xe6, 0x9c, 0x6b, 0x54, 0xda, 0xf1, 0xdd,
0x48, 0xf9, 0xd7, 0xf0, 0x35, 0x7c, 0x8e, 0x24,
0x7e, 0x44, 0x2f, 0xf3, 0xbf, 0x39, 0x0e, 0x96,
0xab, 0xe1, 0x45, 0x03, 0x8b, 0x54, 0xdc, 0xe1,
0xb6, 0x11, 0x81, 0x21, 0x02, 0x03, 0x01, 0x00,
0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06,
0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
0xa4, 0xef, 0x6d, 0xdc, 0x9b, 0x23, 0xc5, 0x3a,
0xdd, 0x34, 0xd9, 0x01, 0x1c, 0x68, 0x03, 0x53,
0xae, 0x92, 0xc2, 0xc9, 0x30, 0x1f, 0x06, 0x03,
0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
0x14, 0xa4, 0xef, 0x6d, 0xdc, 0x9b, 0x23, 0xc5,
0x3a, 0xdd, 0x34, 0xd9, 0x01, 0x1c, 0x68, 0x03,
0x53, 0xae, 0x92, 0xc2, 0xc9, 0x30, 0x0c, 0x06,
0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03,
0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x67,
0x65, 0xbf, 0x93, 0x89, 0xde, 0x4f, 0x71, 0xff,
0x1c, 0x93, 0x68, 0xa0, 0x64, 0x09, 0x5e, 0x95,
0x94, 0xf5, 0xd5, 0xf4, 0x6b, 0x20, 0x32, 0xd8,
0x04, 0x80, 0xac, 0xf8, 0x52, 0x36, 0x7a, 0x38,
0x83, 0xae, 0xab, 0x29, 0x22, 0x42, 0x71, 0x7e,
0xea, 0xe5, 0x4f, 0x71, 0xac, 0x44, 0x3f, 0x9e,
0x5e, 0x49, 0x22, 0x05, 0xee, 0xa6, 0x7b, 0xab,
0x56, 0x2e, 0xb3, 0x9a, 0x35, 0x1a, 0x88, 0xc3,
0x54, 0x9b, 0xfd, 0xac, 0x65, 0x54, 0xaf, 0x21,
0xa7, 0xe0, 0xdd, 0x62, 0x29, 0x8c, 0xae, 0x26,
0x0b, 0x84, 0x1f, 0x69, 0x78, 0x84, 0xc6, 0x7e,
0xcf, 0xc8, 0xf5, 0x92, 0x8c, 0x05, 0xa8, 0x13,
0x38, 0xcd, 0x0b, 0x98, 0x53, 0xfb, 0xdd, 0x8d,
0x51, 0x90, 0xa8, 0x51, 0xfa, 0x52, 0xbe, 0x28,
0xd4, 0x71, 0x50, 0x73, 0x1f, 0xb0, 0xb6, 0x0e,
0x45, 0xb1, 0x47, 0x41, 0x06, 0xd9, 0x1d, 0x7a,
0x34, 0xe7, 0x80, 0x2e, 0x0c, 0x02, 0x50, 0x97,
0xde, 0xa8, 0x7a, 0x84, 0x2c, 0x1d, 0xf4, 0x51,
0x56, 0xa5, 0x52, 0xb5, 0x04, 0x2e, 0xcb, 0xdd,
0x8b, 0x2e, 0x16, 0xc6, 0xde, 0xc8, 0xe9, 0x8d,
0xee, 0x5e, 0xb6, 0xa0, 0xe0, 0x2b, 0x85, 0x2a,
0x89, 0x7b, 0xba, 0x68, 0x80, 0x2b, 0xfb, 0x6e,
0x2e, 0x80, 0xe7, 0x7a, 0x97, 0x09, 0xb5, 0x2f,
0x20, 0x8e, 0xed, 0xbc, 0x98, 0x6f, 0x95, 0xd5,
0x5b, 0x3d, 0x26, 0x19, 0x26, 0x14, 0x39, 0x82,
0xa8, 0xa8, 0x42, 0x46, 0xab, 0x59, 0x93, 0x47,
0x83, 0xf7, 0x79, 0xbf, 0x73, 0xb5, 0x5d, 0x5d,
0x78, 0xfe, 0x62, 0xac, 0xed, 0xb7, 0x1e, 0x4a,
0xad, 0xc3, 0x99, 0x39, 0x7d, 0x3e, 0x30, 0x21,
0x26, 0x1d, 0x66, 0xdb, 0x0d, 0xf3, 0xba, 0x87,
0x46, 0xf0, 0x04, 0xfc, 0xc3, 0xbe, 0x84, 0x85,
0x3c, 0x01, 0xef, 0xe0, 0x68, 0x65, 0xee,
};
#endif /* MBEDTLS_X509_CRT_PARSE_C */
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
/* Avoid leading zero in psk because there's a potential issue of mosquitto
* that leading zero of psk will be skipped and it leads to TLS handshake
* failure
*/
const unsigned char client_psk[] = {
0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
const char client_psk_id[] = "Client_identity";
#endif
#endif /* CONFIG_NET_SOCKETS_OFFLOAD */
#endif