summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cethcan/cethcan.json10
-rw-r--r--cethcan/light.c94
2 files changed, 93 insertions, 11 deletions
diff --git a/cethcan/cethcan.json b/cethcan/cethcan.json
index ae84cb4..7aedf31 100644
--- a/cethcan/cethcan.json
+++ b/cethcan/cethcan.json
@@ -15,7 +15,15 @@
{ "addr": 1095, "name": "dali.hacklab.west.inner" },
{ "addr": 1096, "name": "dali.hacklab.west.middle" },
{ "addr": 1097, "name": "dali.hacklab.east.inner" },
- { "addr": 1098, "name": "dali.hacklab.west.outer" }
+ { "addr": 1098, "name": "dali.hacklab.west.outer" },
+ { "name": "dali.hacklab", "slaves": [
+ "dali.hacklab.east.outer",
+ "dali.hacklab.east.middle",
+ "dali.hacklab.west.inner",
+ "dali.hacklab.west.middle",
+ "dali.hacklab.east.inner",
+ "dali.hacklab.west.outer"
+ ]}
],
"beans": [
{ "addr": 256, "name": "toilet.lock", "values": [ "open", "closed" ] },
diff --git a/cethcan/light.c b/cethcan/light.c
index da6aefb..e3b20a9 100644
--- a/cethcan/light.c
+++ b/cethcan/light.c
@@ -10,7 +10,11 @@ struct light {
struct can_user *u;
char *name;
+ bool aggregate;
+
unsigned logical_addr;
+ size_t slave_count;
+ struct light **slaves;
struct value set, actual;
};
@@ -28,6 +32,13 @@ struct light *light_find(const char *name)
int light_set(struct light *l, unsigned value)
{
+ if (l->aggregate) {
+ int ec = 0;
+ for (size_t i = 0; i < l->slave_count; i++)
+ ec |= light_set(l->slaves[i], value);
+ return ec;
+ }
+
struct can_message msg;
msg.daddr = CANA_LIGHT_F(0, l->logical_addr);
msg.dlc = 1;
@@ -39,31 +50,60 @@ int light_set(struct light *l, unsigned value)
unsigned light_getset(struct light *l)
{
+ if (l->aggregate) {
+ unsigned long long sum = 0;
+ size_t count = 0;
+
+ for (size_t i = 0; i < l->slave_count; i++) {
+ sum += light_getset(l->slaves[i]);
+ count++;
+ }
+
+ if (count)
+ return sum / count;
+ return 0;
+ }
+
return l->set.val;
}
unsigned light_getact(struct light *l)
{
+ if (l->aggregate) {
+ unsigned long long sum = 0;
+ size_t count = 0;
+
+ for (size_t i = 0; i < l->slave_count; i++) {
+ sum += light_getact(l->slaves[i]);
+ count++;
+ }
+
+ if (count)
+ return sum / count;
+ return 0;
+ }
+
return l->actual.val;
}
static void light_json_handler(void *arg, json_t *json, enum json_subtype type)
{
struct light *l = arg;
+ struct light *p = l->aggregate ? l->slaves[0] : l;
json_t *lobj = json_object();
json_object_set_new(lobj, "klass", json_string("light"));
- json_object_set_new(lobj, "addr", json_integer(l->logical_addr));
+ json_object_set_new(lobj, "addr", json_integer(p->logical_addr));
- json_object_set_new(lobj, "actual", json_integer(l->actual.val));
+ json_object_set_new(lobj, "actual", json_integer(light_getact(l)));
if (type != JSON_LONGPOLL)
- json_object_set_new(lobj, "actual_ts", json_integer(l->actual.valid));
- json_object_set_new(lobj, "actual_tschg", json_integer(l->actual.change));
+ json_object_set_new(lobj, "actual_ts", json_integer(p->actual.valid));
+ json_object_set_new(lobj, "actual_tschg", json_integer(p->actual.change));
- json_object_set_new(lobj, "set", json_integer(l->set.val));
+ json_object_set_new(lobj, "set", json_integer(light_getset(l)));
if (type != JSON_LONGPOLL)
- json_object_set_new(lobj, "set_ts", json_integer(l->set.valid));
- json_object_set_new(lobj, "set_tschg", json_integer(l->set.change));
+ json_object_set_new(lobj, "set_ts", json_integer(p->set.valid));
+ json_object_set_new(lobj, "set_tschg", json_integer(p->set.change));
json_object_set_new(json, l->name, lobj);
}
@@ -75,6 +115,9 @@ static void light_can_handler(void *arg, struct can_message *msg)
unsigned laddr;
uint8_t dval;
+ if (l->aggregate)
+ return;
+
if ((msg->daddr & CANA_PROTOCOL) == CANA_LIGHT)
v = &l->set;
if ((msg->daddr & CANA_PROTOCOL) == CANA_SENSOR)
@@ -102,15 +145,21 @@ static void light_can_handler(void *arg, struct can_message *msg)
int light_init_conf(json_t *config)
{
struct light *l;
+ bool aggregate;
if (!json_is_object(config)) {
lprintf("light config must be an object/dictionary");
return 1;
}
- if (!json_is_integer(json_object_get(config, "addr"))) {
- lprintf("light config must have an 'addr' key");
+ if (json_is_integer(json_object_get(config, "addr"))) {
+ aggregate = false;
+ } else if (json_is_array(json_object_get(config, "slaves"))) {
+ aggregate = true;
+ } else {
+ lprintf("light config must have an 'addr' key or 'saves'.");
return 1;
}
+
if (!json_is_string(json_object_get(config, "name"))) {
lprintf("light config must have a 'name' key");
return 1;
@@ -118,7 +167,32 @@ int light_init_conf(json_t *config)
l = calloc(sizeof(*l), 1);
l->name = strdup(json_string_value(json_object_get(config, "name")));
- l->logical_addr = json_integer_value(json_object_get(config, "addr"));
+ l->aggregate = aggregate;
+
+ if (aggregate) {
+ json_t *slaves = json_object_get(config, "slaves");
+ l->slave_count = json_array_size(slaves);
+ if (!l->slave_count) {
+ lprintf("Slave array must not be empty.");
+ return 1;
+ }
+
+ l->slaves = calloc(l->slave_count, sizeof(*l->slaves));
+ for (size_t i = 0; i < json_array_size(slaves); i++) {
+ const char *name = json_string_value(
+ json_array_get(slaves, i)
+ );
+ l->slaves[i] = light_find(name);
+ if (!l->slaves[i]) {
+ lprintf("Unknown slave '%s'", name);
+ return 1;
+ }
+ }
+ } else {
+ l->logical_addr = json_integer_value(
+ json_object_get(config, "addr")
+ );
+ }
l->u = can_register_alloc(l, light_can_handler, "light[%s]", l->name);
l->u->json = light_json_handler;