Rewrite statusled implementation.
- Read it now from app.config JSON file. - Allow for inverted status leds (Sonoff et al) - Clean up unit tests.
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Sonoff 4CH v1.1",
|
"name": "Sonoff 4CH v1.1",
|
||||||
"status_led": 13,
|
"statusled": 13,
|
||||||
|
"statusled_invert": true,
|
||||||
"channels": [
|
"channels": [
|
||||||
{ "led": -1, "relay": 15, "button": 14 },
|
{ "led": -1, "relay": 15, "button": 14 },
|
||||||
{ "led": -1, "relay": 4, "button": 10 },
|
{ "led": -1, "relay": 4, "button": 10 },
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Sonoff Basic, S20, SV, RF, TH, Touch",
|
"name": "Sonoff Basic, S20, SV, RF, TH, Touch",
|
||||||
"status_led": 13,
|
"statusled": 13,
|
||||||
|
"statusled_invert": true,
|
||||||
"channels": [
|
"channels": [
|
||||||
{ "led": -1, "relay": 12, "button": 0 }
|
{ "led": -1, "relay": 12, "button": 0 }
|
||||||
]
|
]
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#define CHANNEL_CHANGE_COOLDOWN_SECONDS 0.250
|
#define CHANNEL_CHANGE_COOLDOWN_SECONDS 0.250
|
||||||
#define CHANNEL_MAX 16
|
#define CHANNEL_MAX 16
|
||||||
#define GREEN_LED_GPIO 0
|
|
||||||
#define GPIO_INVALID 255
|
#define GPIO_INVALID 255
|
||||||
#define GPIO_MIN 0
|
#define GPIO_MIN 0
|
||||||
#define GPIO_MAX 16
|
#define GPIO_MAX 16
|
||||||
@ -19,7 +18,8 @@ struct channel_t {
|
|||||||
double button_last_change;
|
double button_last_change;
|
||||||
};
|
};
|
||||||
|
|
||||||
void led_status_blink();
|
void statusled_blink();
|
||||||
|
void statusled_init(uint8_t gpio, bool state_off);
|
||||||
|
|
||||||
bool channel_init(const char *fn);
|
bool channel_init(const char *fn);
|
||||||
uint8_t channel_gpio_by_idx(int idx);
|
uint8_t channel_gpio_by_idx(int idx);
|
||||||
|
@ -24,7 +24,8 @@ bool channel_init(const char *fn) {
|
|||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
int status_led = -1;
|
int statusled = -1;
|
||||||
|
bool statusled_invert = false;
|
||||||
|
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
@ -37,15 +38,19 @@ bool channel_init(const char *fn) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json_scanf(json, strlen(json), "{name:%Q, status_led:%d}", &name, &status_led) != 2) {
|
if (json_scanf(json, strlen(json), "{name:%Q, statusled:%d}", &name, &statusled) != 2) {
|
||||||
LOG(LL_ERROR, ("Incomplete JSON: require 'name' and 'status_led' fields"));
|
LOG(LL_ERROR, ("Incomplete JSON: require 'name' and 'statusled' fields"));
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
LOG(LL_INFO, ("Configuration: name='%s', status_led=%d", name, status_led));
|
LOG(LL_INFO, ("Configuration: name='%s', statusled=%d", name, statusled));
|
||||||
if (!valid_gpio(status_led)) {
|
if (!valid_gpio(statusled)) {
|
||||||
LOG(LL_ERROR, ("Status LED GPIO (%d) out of bounds [%d,%d]", status_led, GPIO_MIN, GPIO_MAX));
|
LOG(LL_ERROR, ("Status LED GPIO (%d) out of bounds [%d,%d]", statusled, GPIO_MIN, GPIO_MAX));
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
json_scanf(json, strlen(json), "{statusled_invert:%B}", &statusled_invert);
|
||||||
|
if (statusled_invert) {
|
||||||
|
LOG(LL_INFO, ("Inverting statusled GPIO (%d)", statusled));
|
||||||
|
}
|
||||||
|
|
||||||
// Traverse Array
|
// Traverse Array
|
||||||
while ((h = json_next_elem(json, strlen(json), h, ".channels", &idx, &val)) != NULL) {
|
while ((h = json_next_elem(json, strlen(json), h, ".channels", &idx, &val)) != NULL) {
|
||||||
@ -83,10 +88,8 @@ bool channel_init(const char *fn) {
|
|||||||
ret=true;
|
ret=true;
|
||||||
exit:
|
exit:
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (status_led!=-1) {
|
if (statusled!=-1)
|
||||||
mgos_gpio_set_mode(status_led, MGOS_GPIO_MODE_OUTPUT);
|
statusled_init(statusled,statusled_invert);
|
||||||
mgos_gpio_write(status_led, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
s_num_channels=idx+1;
|
s_num_channels=idx+1;
|
||||||
LOG(LL_INFO, ("Configuring %d channels", s_num_channels));
|
LOG(LL_INFO, ("Configuring %d channels", s_num_channels));
|
||||||
|
20
src/led.c
20
src/led.c
@ -1,20 +0,0 @@
|
|||||||
#include "main.h"
|
|
||||||
|
|
||||||
static mgos_timer_id led_status_timer_id = 0;
|
|
||||||
|
|
||||||
static void led_status_off_cb(void *arg) {
|
|
||||||
mgos_gpio_write(GREEN_LED_GPIO, 0);
|
|
||||||
led_status_timer_id=0;
|
|
||||||
(void) arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void led_status_blink() {
|
|
||||||
mgos_gpio_write(GREEN_LED_GPIO, 1);
|
|
||||||
if (led_status_timer_id) {
|
|
||||||
mgos_clear_timer(led_status_timer_id);
|
|
||||||
led_status_timer_id=0;
|
|
||||||
}
|
|
||||||
led_status_timer_id = mgos_set_timer(100, false, led_status_off_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -4,9 +4,6 @@
|
|||||||
#include "rpc.h"
|
#include "rpc.h"
|
||||||
|
|
||||||
enum mgos_app_init_result mgos_app_init(void) {
|
enum mgos_app_init_result mgos_app_init(void) {
|
||||||
mgos_gpio_set_mode(GREEN_LED_GPIO, MGOS_GPIO_MODE_OUTPUT);
|
|
||||||
mgos_gpio_write(GREEN_LED_GPIO, 0);
|
|
||||||
|
|
||||||
channel_init(mgos_sys_config_get_app_config());
|
channel_init(mgos_sys_config_get_app_config());
|
||||||
mqtt_init();
|
mqtt_init();
|
||||||
rpc_init();
|
rpc_init();
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
static void mqtt_publish_broadcast_stat(const char *stat, const char *msg) {
|
static void mqtt_publish_broadcast_stat(const char *stat, const char *msg) {
|
||||||
char topic[80];
|
char topic[80];
|
||||||
|
|
||||||
led_status_blink();
|
statusled_blink();
|
||||||
|
|
||||||
snprintf(topic, sizeof(topic)-1, "%s/%s", MQTT_TOPIC_BROADCAST_STAT, stat);
|
snprintf(topic, sizeof(topic)-1, "%s/%s", MQTT_TOPIC_BROADCAST_STAT, stat);
|
||||||
mgos_mqtt_pub((char*)topic, (char*)msg, strlen(msg), 0, false);
|
mgos_mqtt_pub((char*)topic, (char*)msg, strlen(msg), 0, false);
|
||||||
@ -62,7 +62,7 @@ static void mqtt_ev(struct mg_connection *nc, int ev, void *ev_data, void *user_
|
|||||||
void mqtt_publish_stat(const char *stat, const char *msg) {
|
void mqtt_publish_stat(const char *stat, const char *msg) {
|
||||||
char topic[80];
|
char topic[80];
|
||||||
|
|
||||||
led_status_blink();
|
statusled_blink();
|
||||||
|
|
||||||
snprintf(topic, sizeof(topic)-1, "%s%s/stat/%s", MQTT_TOPIC_PREFIX, mgos_sys_config_get_device_id(), stat);
|
snprintf(topic, sizeof(topic)-1, "%s%s/stat/%s", MQTT_TOPIC_PREFIX, mgos_sys_config_get_device_id(), stat);
|
||||||
mgos_mqtt_pub((char*)topic, (char*)msg, strlen(msg), 0, false);
|
mgos_mqtt_pub((char*)topic, (char*)msg, strlen(msg), 0, false);
|
||||||
|
30
src/statusled.c
Normal file
30
src/statusled.c
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
static mgos_timer_id statusled_timer_id = 0;
|
||||||
|
static uint8_t statusled_gpio = 0;
|
||||||
|
static bool statusled_off_state = 0;
|
||||||
|
|
||||||
|
static void statusled_off_cb(void *arg) {
|
||||||
|
mgos_gpio_write(statusled_gpio, statusled_off_state);
|
||||||
|
statusled_timer_id=0;
|
||||||
|
(void) arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void statusled_blink() {
|
||||||
|
if (statusled_gpio == GPIO_INVALID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mgos_gpio_write(statusled_gpio, !statusled_off_state);
|
||||||
|
if (statusled_timer_id) {
|
||||||
|
mgos_clear_timer(statusled_timer_id);
|
||||||
|
statusled_timer_id=0;
|
||||||
|
}
|
||||||
|
statusled_timer_id = mgos_set_timer(100, false, statusled_off_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void statusled_init(uint8_t gpio, bool off_state) {
|
||||||
|
statusled_gpio = gpio;
|
||||||
|
statusled_off_state = off_state;
|
||||||
|
mgos_gpio_set_mode(statusled_gpio, MGOS_GPIO_MODE_OUTPUT);
|
||||||
|
mgos_gpio_write(statusled_gpio, statusled_off_state);
|
||||||
|
}
|
@ -9,7 +9,7 @@ default: $(TARGET)
|
|||||||
all: default
|
all: default
|
||||||
|
|
||||||
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
|
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
|
||||||
SRCS = frozen/frozen.c ../src/channel.c ../src/mqtt.c ../src/led.c
|
SRCS = frozen/frozen.c ../src/channel.c ../src/mqtt.c ../src/statusled.c
|
||||||
HEADERS = $(wildcard *.h)
|
HEADERS = $(wildcard *.h)
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
%.o: %.c $(HEADERS)
|
||||||
|
5
unittest/testdata/testconfig0.json
vendored
5
unittest/testdata/testconfig0.json
vendored
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "3 Gang",
|
"name": "3 Gang, inverted statusled",
|
||||||
"status_led": 0,
|
"statusled": 9,
|
||||||
|
"statusled_invert": true,
|
||||||
"channels": [
|
"channels": [
|
||||||
{ "led": 2, "relay": 15, "button": 5 },
|
{ "led": 2, "relay": 15, "button": 5 },
|
||||||
{ "led": 14, "relay": 4, "button": 3 },
|
{ "led": 14, "relay": 4, "button": 3 },
|
||||||
|
2
unittest/testdata/testconfig1.json
vendored
2
unittest/testdata/testconfig1.json
vendored
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "3 Gang, No LEDs",
|
"name": "3 Gang, No LEDs",
|
||||||
"status_led": -1,
|
"statusled": -1,
|
||||||
"channels": [
|
"channels": [
|
||||||
{ "led": -1, "relay": 15, "button": 5 },
|
{ "led": -1, "relay": 15, "button": 5 },
|
||||||
{ "led": -1, "relay": 4, "button": 3 },
|
{ "led": -1, "relay": 4, "button": 3 },
|
||||||
|
Reference in New Issue
Block a user