|
|
|
@ -56,8 +56,8 @@ bool channel_init(const char *fn) {
|
|
|
|
|
|
|
|
|
|
// Traverse Array
|
|
|
|
|
while ((h = json_next_elem(json, strlen(json), h, ".channels", &idx, &val)) != NULL) {
|
|
|
|
|
int led = -1, relay = -1, button = -1;
|
|
|
|
|
bool led_invert = false;
|
|
|
|
|
int led = -1, relay = -1, button = -1;
|
|
|
|
|
bool led_invert = false;
|
|
|
|
|
bool relay_invert = false;
|
|
|
|
|
|
|
|
|
|
LOG(LL_DEBUG, ("[%d]: [%.*s]", idx, val.len, val.ptr));
|
|
|
|
@ -85,12 +85,12 @@ bool channel_init(const char *fn) {
|
|
|
|
|
LOG(LL_ERROR, ("Too many channels (max is %d)", CHANNEL_MAX));
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
LOG(LL_INFO, ("Channel[%d]: led=%d%s relay=%d%s button=%d ", idx, led, led_invert?"(inverted)":"", relay, relay_invert?"(inverted)":"", button));
|
|
|
|
|
s_channels[idx].button_gpio = button;
|
|
|
|
|
s_channels[idx].relay_gpio = relay;
|
|
|
|
|
s_channels[idx].relay_invert= relay_invert;
|
|
|
|
|
s_channels[idx].led_gpio = led;
|
|
|
|
|
s_channels[idx].led_invert = led_invert;
|
|
|
|
|
LOG(LL_INFO, ("Channel[%d]: led=%d%s relay=%d%s button=%d ", idx, led, led_invert ? "(inverted)" : "", relay, relay_invert ? "(inverted)" : "", button));
|
|
|
|
|
s_channels[idx].button_gpio = button;
|
|
|
|
|
s_channels[idx].relay_gpio = relay;
|
|
|
|
|
s_channels[idx].relay_invert = relay_invert;
|
|
|
|
|
s_channels[idx].led_gpio = led;
|
|
|
|
|
s_channels[idx].led_invert = led_invert;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
@ -108,17 +108,17 @@ exit:
|
|
|
|
|
|
|
|
|
|
if (s_channels[idx].relay_gpio != GPIO_INVALID) {
|
|
|
|
|
mgos_gpio_set_mode(s_channels[idx].relay_gpio, MGOS_GPIO_MODE_OUTPUT);
|
|
|
|
|
mgos_gpio_write(s_channels[idx].relay_gpio, (s_channels[idx].relay_state + s_channels[idx].relay_invert)%2);
|
|
|
|
|
mgos_gpio_write(s_channels[idx].relay_gpio, (s_channels[idx].relay_state + s_channels[idx].relay_invert) % 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (s_channels[idx].led_gpio != GPIO_INVALID) {
|
|
|
|
|
mgos_gpio_set_mode(s_channels[idx].led_gpio, MGOS_GPIO_MODE_OUTPUT);
|
|
|
|
|
mgos_gpio_write(s_channels[idx].led_gpio, (s_channels[idx].relay_state + s_channels[idx].led_invert)%2);
|
|
|
|
|
mgos_gpio_write(s_channels[idx].led_gpio, (s_channels[idx].relay_state + s_channels[idx].led_invert) % 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (s_channels[idx].button_gpio != GPIO_INVALID) {
|
|
|
|
|
mgos_gpio_set_mode(s_channels[idx].button_gpio, MGOS_GPIO_MODE_INPUT);
|
|
|
|
|
mgos_gpio_set_button_handler(s_channels[idx].button_gpio, MGOS_GPIO_PULL_UP, MGOS_GPIO_INT_EDGE_NEG, 20, channel_handler, (void*) 1);
|
|
|
|
|
mgos_gpio_set_button_handler(s_channels[idx].button_gpio, MGOS_GPIO_PULL_UP, MGOS_GPIO_INT_EDGE_NEG, 20, channel_handler, (void *)1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -151,11 +151,12 @@ uint8_t channel_idx_by_gpio(int gpio) {
|
|
|
|
|
|
|
|
|
|
struct channel_set_cb_args {
|
|
|
|
|
uint8_t idx;
|
|
|
|
|
bool value;
|
|
|
|
|
bool value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void channel_set_cb(void *arg) {
|
|
|
|
|
struct channel_set_cb_args *cb_args = (struct channel_set_cb_args *)arg;
|
|
|
|
|
|
|
|
|
|
if (!arg) {
|
|
|
|
|
LOG(LL_ERROR, ("Callback arg is NULL"));
|
|
|
|
|
return;
|
|
|
|
@ -177,9 +178,9 @@ void channel_set_duration(int idx, bool state, uint16_t seconds) {
|
|
|
|
|
|
|
|
|
|
// Set a timer to call back with the new intended state on the channel.
|
|
|
|
|
cb_args->value = !state;
|
|
|
|
|
cb_args->idx = idx;
|
|
|
|
|
cb_args->idx = idx;
|
|
|
|
|
LOG(LL_INFO, ("Setting timer for %d seconds on channel %d with future value %d", seconds, cb_args->idx, cb_args->value));
|
|
|
|
|
mgos_set_timer (1000 * seconds, false /* oneshot */, channel_set_cb, cb_args);
|
|
|
|
|
mgos_set_timer(1000 * seconds, false /* oneshot */, channel_set_cb, cb_args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void channel_set(int idx, bool state) {
|
|
|
|
@ -192,10 +193,10 @@ void channel_set(int idx, bool state) {
|
|
|
|
|
s_channels[idx].button_last_change = now;
|
|
|
|
|
s_channels[idx].relay_state = state;
|
|
|
|
|
if (s_channels[idx].relay_gpio != GPIO_INVALID) {
|
|
|
|
|
mgos_gpio_write(s_channels[idx].relay_gpio, (s_channels[idx].relay_state + s_channels[idx].relay_invert)%2);
|
|
|
|
|
mgos_gpio_write(s_channels[idx].relay_gpio, (s_channels[idx].relay_state + s_channels[idx].relay_invert) % 2);
|
|
|
|
|
}
|
|
|
|
|
if (s_channels[idx].led_gpio != GPIO_INVALID) {
|
|
|
|
|
mgos_gpio_write(s_channels[idx].led_gpio, (s_channels[idx].relay_state + s_channels[idx].led_invert)%2);
|
|
|
|
|
mgos_gpio_write(s_channels[idx].led_gpio, (s_channels[idx].relay_state + s_channels[idx].led_invert) % 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mqtt_publish_stat("channel", "{idx: %d, relay_state: %d}", idx, channel_get(idx));
|
|
|
|
@ -233,13 +234,13 @@ void channel_handler(int gpio, void *arg) {
|
|
|
|
|
LOG(LL_INFO, ("Button on GPIO %d triggered channel %d", gpio, idx));
|
|
|
|
|
// Scan the button for 100ms to ensure it is still pressed. This is to avoid
|
|
|
|
|
// RFI noise from triggering GPIO pins.
|
|
|
|
|
for (int i=0; i<10; i++) {
|
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
|
bool value;
|
|
|
|
|
|
|
|
|
|
mgos_msleep(10);
|
|
|
|
|
value=mgos_gpio_read(gpio);
|
|
|
|
|
value = mgos_gpio_read(gpio);
|
|
|
|
|
if (value) {
|
|
|
|
|
LOG(LL_WARN, ("Button on GPIO %d no longer pressed after %d ms, skipping", gpio, 10*i));
|
|
|
|
|
LOG(LL_WARN, ("Button on GPIO %d no longer pressed after %d ms, skipping", gpio, 10 * i));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|