changeset 242:d23d6fbb50df

Finally fix bulb printing, nice refactor and print ipv4 mapped ipv6 addresses
author Louis Opter <kalessin@kalessin.fr>
date Thu, 13 Aug 2015 02:29:45 -0700
parents aaa04a77415b
children 1e98f511dc00
files fix_ipv4_address_formatting.patch implement_some_metadata_packet_types.patch series
diffstat 3 files changed, 191 insertions(+), 203 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fix_ipv4_address_formatting.patch	Thu Aug 13 02:29:45 2015 -0700
@@ -0,0 +1,40 @@
+# HG changeset patch
+# Parent  9a3306521fe5002bdaf61c06d6d74ae5abc3d38e
+Fix IPv4 address formatting
+
+diff --git a/core/log.c b/core/log.c
+--- a/core/log.c
++++ b/core/log.c
+@@ -26,6 +26,7 @@
+ #include <stdbool.h>
+ #include <stdint.h>
+ #include <stdio.h>
++#include <stdlib.h>
+ #include <time.h>
+ 
+ #if LGTD_HAVE_LIBBSD
+@@ -93,12 +94,22 @@
+     assert(buf);
+     assert(buflen > 0);
+ 
++    const char *printed;
+     if (peer->ss_family == AF_INET) {
+         const struct sockaddr_in *in_peer = (const struct sockaddr_in *)peer;
+-        inet_ntop(AF_INET, &in_peer->sin_addr, buf, buflen);
++        int i = 0;
++        LGTD_SNPRINTF_APPEND(buf, i, buflen, "::ffff:");
++        printed = inet_ntop(AF_INET, &in_peer->sin_addr, &buf[i], buflen - i);
+     } else {
+         const struct sockaddr_in6 *in6_peer = (const struct sockaddr_in6 *)peer;
+-        inet_ntop(AF_INET6, &in6_peer->sin6_addr, buf, buflen);
++        printed = inet_ntop(AF_INET6, &in6_peer->sin6_addr, buf, buflen);
++    }
++    if (!printed) {
++        buf[0] = 0;
++        lgtd_warnx("not enough space to log an ip address");
++#ifndef NDEBUG
++        abort();
++#endif
+     }
+ }
+ 
--- a/implement_some_metadata_packet_types.patch	Tue Aug 11 00:37:46 2015 -0700
+++ b/implement_some_metadata_packet_types.patch	Thu Aug 13 02:29:45 2015 -0700
@@ -61,7 +61,7 @@
 +#define LGTD_SNPRINTF_APPEND(buf, i, bufsz, ...) do {       \
 +    int n = snprintf(&(buf)[(i)], bufsz - i, __VA_ARGS__);  \
 +    (i) = LGTD_MIN((i) + n, bufsz);                         \
-+while (0)
++} while (0)
  
  enum lgtd_verbosity {
      LGTD_DEBUG = 0,
@@ -126,108 +126,61 @@
 diff --git a/core/proto.c b/core/proto.c
 --- a/core/proto.c
 +++ b/core/proto.c
-@@ -196,6 +196,40 @@
+@@ -195,36 +195,108 @@
+         return;
      }
  
-     static const char *state_fmt = ("{"
-+        "\"_lifx\":{"
-+            "\"gateway\":{"
-+                "\"url\":\"tcp://%s:[%hu]\","
-+                "\"latency\":%d"
-+            "},"
-+            "\"mcu\":{"
-+                "\"firmware_built_at\":\"%s\","
-+                "\"firmware_installed_at\":\"%s\","
-+                "\"firmware_version\":%u,"
-+                "\"signal_strength\":%u,"
-+                "\"tx_bytes\":%u,"
-+                "\"rx_bytes\":%u,"
-+                "\"unknown\":%u"
-+            "},"
-+            "\"wifi\":{"
-+                "\"firmware_built_at\":\"%s\","
-+                "\"firmware_installed_at\":\"%s\","
-+                "\"firmware_version\":%u,"
-+                "\"signal_strength\":%u,"
-+                "\"tx_bytes\":%u,"
-+                "\"rx_bytes\":%u,"
-+                "\"unknown\":%u"
-+            "},"
-+            "\"product_info\":{"
-+                "\"vendor_id\":%#x,"
-+                "\"product_id\":%#x,"
-+                "\"version\":%u"
-+            "},"
-+            "\"runtime_info\":{"
-+                "\"time\":\"%s\","
-+                "\"uptime\":%ju,"
-+                "\"downtime\":%ju"
-+            "}"
-+        "},"
-         "\"hsbk\":[%s,%s,%s,%hu],"
-         "\"power\":%s,"
-         "\"label\":\"%s\","
-@@ -206,6 +240,12 @@
-         (src), (start), (stop), (dst), sizeof((dst))    \
-     )
- 
+-    static const char *state_fmt = ("{"
+-        "\"hsbk\":[%s,%s,%s,%hu],"
+-        "\"power\":%s,"
+-        "\"label\":\"%s\","
+-        "\"tags\":[");
++    lgtd_client_start_send_response(client);
++    lgtd_client_write_string(client, "[");
++    struct lgtd_router_device *device;
++    SLIST_FOREACH(device, devices, link) {
++        struct lgtd_lifx_bulb *bulb = device->device;
++
++        char buf[2048];
++        int i = 0;
++
++        LGTD_SNPRINTF_APPEND(
++            buf, i, (int)sizeof(buf),
++            "{"
++                "\"_lifx\":{"
++                    "\"gateway\":{"
++                        "\"url\":\"tcp://[%s]:%hu\","
++                        "\"latency\":%ju"
++                    "},",
++            bulb->gw->ip_addr, bulb->gw->port,
++            (uintmax_t)LGTD_LIFX_GATEWAY_LATENCY(bulb->gw)
++        );
++
 +#define PRINT_LIFX_FW_TIMESTAMPS(fw_info, built_at_buf, installed_at_buf)       \
 +    LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP((fw_info)->built_at, (built_at_buf));   \
 +    LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(                                        \
 +        (fw_info)->installed_at, (installed_at_buf)                             \
 +    )
 +
-     lgtd_client_start_send_response(client);
-     lgtd_client_write_string(client, "[");
-     struct lgtd_router_device *device;
-@@ -217,14 +257,91 @@
-         PRINT_COMPONENT(bulb->state.saturation, s, 0, 1);
-         PRINT_COMPONENT(bulb->state.brightness, b, 0, 1);
- 
--        char buf[3072];
--        int written = snprintf(
--            buf, sizeof(buf), state_fmt,
-+        char mcu_fw_built_at[64], mcu_fw_installed_at[64], bulb_time[64];
-+        LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(bulb->runtime_info.time, bulb_time);
-+        PRINT_LIFX_FW_TIMESTAMPS(
-+            &bulb->mcu_fw_info, mcu_fw_built_at, mcu_fw_installed_at
-+        );
++        for (int ip = 0; ip != LGTD_LIFX_BULB_IP_COUNT; ip++) {
++            char fw_built_at[64], fw_installed_at[64];
++            PRINT_LIFX_FW_TIMESTAMPS(
++                &bulb->ips[ip].fw_info, fw_built_at, fw_installed_at
++            );
 +
-+        char wifi_fw_built_at[64], wifi_fw_installed_at[64];
-+        PRINT_LIFX_FW_TIMESTAMPS(
-+            &bulb->wifi_fw_info, wifi_fw_built_at, wifi_fw_installed_at
-+        );
-+
-+        char buf[2048];
-+        int i = 0;
-+
-+        LGTD_SNPRINTF_APPEND(
-+            buf, i, (int)sizeof(buf), "{"
-+                "\"_lifx\":{"
-+                    "\"gateway\":{"
-+                        "\"url\":\"tcp://%s:[%hu]\","
-+                        "\"latency\":%d"
-+                    "},",
-+            bulb->gw->ip_addr, bulb->gw->port,
-+            LGTD_LIFX_GATEWAY_LATENCY(bulb->gw)
-+        );
-+
-+        for (int ip = 0; ip != LGTD_LIFX_BULB_IP_COUNT; ip++) {
 +            LGTD_SNPRINTF_APPEND(
 +                buf, i, (int)sizeof(buf),
 +                "\"%s\":{"
 +                    "\"firmware_built_at\":\"%s\","
 +                    "\"firmware_installed_at\":\"%s\","
 +                    "\"firmware_version\":%u,"
-+                    "\"signal_strength\":%u,"
++                    "\"signal_strength\":%f,"
 +                    "\"tx_bytes\":%u,"
 +                    "\"rx_bytes\":%u,"
 +                    "\"unknown\":%u"
 +                "},",
 +                lgtd_lifx_bulb_ip_names[ip],
-+                bulb->ips[ip].fw_info.built_at,
-+                bulb->ips[ip].fw_info.installed_at,
-+                bulb->ips[ip].fw_info.version,
++                fw_built_at, fw_installed_at, bulb->ips[ip].fw_info.version,
 +                bulb->ips[ip].state.signal_strength,
 +                bulb->ips[ip].state.tx_bytes,
 +                bulb->ips[ip].state.rx_bytes,
@@ -244,9 +197,11 @@
 +                "},",
 +            bulb->product_info.vendor_id,
 +            bulb->product_info.product_id,
-+            bulb->product_info.version,
++            bulb->product_info.version
 +        );
 +
++        char bulb_time[64];
++        LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(bulb->runtime_info.time, bulb_time);
 +        LGTD_SNPRINTF_APPEND(
 +            buf, i, (int)sizeof(buf),
 +                "\"runtime_info\":{"
@@ -254,12 +209,31 @@
 +                    "\"uptime\":%ju,"
 +                    "\"downtime\":%ju"
 +                "}"
-+            "},"
++            "},",
 +            bulb_time,
 +            LGTD_NSECS_TO_SECS(bulb->runtime_info.uptime),
-+            LGTD_NSECS_TO_SECS(bulb->runtime_info.downtime),
++            LGTD_NSECS_TO_SECS(bulb->runtime_info.downtime)
 +        );
-+
+ 
+ #define PRINT_COMPONENT(src, dst, start, stop)          \
+     lgtd_jsonrpc_uint16_range_to_float_string(          \
+         (src), (start), (stop), (dst), sizeof((dst))    \
+     )
+ 
+-    lgtd_client_start_send_response(client);
+-    lgtd_client_write_string(client, "[");
+-    struct lgtd_router_device *device;
+-    SLIST_FOREACH(device, devices, link) {
+-        struct lgtd_lifx_bulb *bulb = device->device;
+-
+         char h[16], s[16], b[16];
+         PRINT_COMPONENT(bulb->state.hue, h, 0, 360);
+         PRINT_COMPONENT(bulb->state.saturation, s, 0, 1);
+         PRINT_COMPONENT(bulb->state.brightness, b, 0, 1);
+ 
+-        char buf[3072];
+-        int written = snprintf(
+-            buf, sizeof(buf), state_fmt,
 +        LGTD_SNPRINTF_APPEND(
 +            buf, i, (int)sizeof(buf),
 +            "\"hsbk\":[%s,%s,%s,%hu],"
@@ -272,10 +246,22 @@
          );
 -        if (written >= (int)sizeof(buf)) {
 +
-+        if (i == (int)sizeof(buf)) {
++        if (i >= (int)sizeof(buf)) {
              lgtd_warnx(
                  "can't send state of bulb %s (%s) to client "
                  "[%s]:%hu: output buffer to small",
+diff --git a/examples/lightsc.py b/examples/lightsc.py
+--- a/examples/lightsc.py
++++ b/examples/lightsc.py
+@@ -17,7 +17,7 @@
+         "id": str(uuid.uuid4()),
+     }
+     socket.send(json.dumps(payload).encode("utf-8"))
+-    response = socket.recv(2048).decode("utf-8")
++    response = socket.recv(8192).decode("utf-8")
+     try:
+         response = json.loads(response)
+     except ValueError:
 diff --git a/lifx/bulb.c b/lifx/bulb.c
 --- a/lifx/bulb.c
 +++ b/lifx/bulb.c
@@ -283,58 +269,42 @@
  struct lgtd_lifx_bulb_map lgtd_lifx_bulbs_table =
      RB_INITIALIZER(&lgtd_lifx_bulbs_table);
  
-+const const char *lgtd_lifx_bulb_ip_names[] = { "mcu", "wifi" };
++const char * const lgtd_lifx_bulb_ip_names[] = { "mcu", "wifi" };
 +
  struct lgtd_lifx_bulb *
  lgtd_lifx_bulb_get(const uint8_t *addr)
  {
-@@ -154,3 +156,69 @@
+@@ -154,3 +156,53 @@
  
      bulb->state.tags = tags;
  }
 +
 +void
-+lgtd_lifx_bulb_set_mcu_state(struct lgtd_lifx_bulb *bulb,
-+                             const struct lgtd_lifx_ip_state *state,
-+                             lgtd_time_mono_t received_at)
++lgtd_lifx_bulb_set_ip_state(struct lgtd_lifx_bulb *bulb,
++                      enum lgtd_lifx_bulb_ips ip_id,
++                      const struct lgtd_lifx_ip_state *state,
++                      lgtd_time_mono_t received_at)
 +{
 +    assert(bulb);
 +    assert(state);
 +
-+    bulb->last_mcu_state_at = received_at;
-+    memcpy(&bulb->mcu_state, state, sizeof(bulb->mcu_state));
++    struct lgtd_lifx_bulb_ip *ip = &bulb->ips[ip_id];
++    ip->state_updated_at = received_at;
++    memcpy(&ip->state, state, sizeof(ip->state));
 +}
 +
 +void
-+lgtd_lifx_bulb_set_mcu_firmware_info(struct lgtd_lifx_bulb *bulb,
-+                                     const struct lgtd_lifx_ip_firmware_info *info)
++lgtd_lifx_bulb_set_ip_firmware_info(struct lgtd_lifx_bulb *bulb,
++                                    enum lgtd_lifx_bulb_ips ip_id,
++                                    const struct lgtd_lifx_ip_firmware_info *info,
++                                    lgtd_time_mono_t received_at)
 +{
 +    assert(bulb);
 +    assert(info);
 +
-+    memcpy(&bulb->mcu_fw_info, info, sizeof(bulb->mcu_fw_info));
-+}
-+
-+void
-+lgtd_lifx_bulb_set_wifi_state(struct lgtd_lifx_bulb *bulb,
-+                              const struct lgtd_lifx_ip_state *state,
-+                              lgtd_time_mono_t received_at)
-+{
-+    assert(bulb);
-+    assert(state);
-+
-+    bulb->last_wifi_state_at = received_at;
-+    memcpy(&bulb->wifi_state, state, sizeof(bulb->wifi_state));
-+}
-+
-+void
-+lgtd_lifx_bulb_set_wifi_firmware_info(struct lgtd_lifx_bulb *bulb,
-+                                      const struct lgtd_lifx_ip_firmware_info *info)
-+{
-+    assert(bulb);
-+    assert(info);
-+
-+    memcpy(&bulb->wifi_fw_info, info, sizeof(bulb->wifi_fw_info));
++    struct lgtd_lifx_bulb_ip *ip = &bulb->ips[ip_id];
++    ip->fw_info_updated_at = received_at;
++    memcpy(&ip->fw_info, info, sizeof(ip->fw_info));
 +}
 +
 +void
@@ -355,13 +325,13 @@
 +    assert(bulb);
 +    assert(info);
 +
-+    bulb->last_runtime_info_at = received_at;
++    bulb->runtime_info_updated_at = received_at;
 +    memcpy(&bulb->runtime_info, info, sizeof(bulb->runtime_info));
 +}
 diff --git a/lifx/bulb.h b/lifx/bulb.h
 --- a/lifx/bulb.h
 +++ b/lifx/bulb.h
-@@ -30,17 +30,58 @@
+@@ -30,17 +30,61 @@
      char        label[LGTD_LIFX_LABEL_SIZE];
      uint64_t    tags;
  };
@@ -393,56 +363,52 @@
  #pragma pack(pop)
  
 +enum lgtd_lifx_bulb_ips {
-+    LGTD_LIFX_BULB_MCU_IP   = 0,
-+    LGTD_LIFX_BULB_WIFI_IP  = 1,
-+    LGTD_LIFX_BULB_IP_COUNT = 2
++    LGTD_LIFX_BULB_MCU_IP = 0,
++    LGTD_LIFX_BULB_WIFI_IP,
++    LGTD_LIFX_BULB_IP_COUNT,
 +};
 +
-+extern const char *lgtd_lifx_bulb_ip_names[];
++extern const char * const lgtd_lifx_bulb_ip_names[];
++
++struct lgtd_lifx_bulb_ip {
++    struct lgtd_lifx_ip_state           state;
++    lgtd_time_mono_t                    state_updated_at;
++    struct lgtd_lifx_ip_firmware_info   fw_info;
++    lgtd_time_mono_t                    fw_info_updated_at;
++};
 +
  struct lgtd_lifx_bulb {
--    RB_ENTRY(lgtd_lifx_bulb)        link;
--    SLIST_ENTRY(lgtd_lifx_bulb)     link_by_gw;
+     RB_ENTRY(lgtd_lifx_bulb)        link;
+     SLIST_ENTRY(lgtd_lifx_bulb)     link_by_gw;
 -    struct lgtd_lifx_gateway        *gw;
 -    uint8_t                         addr[LGTD_LIFX_ADDR_LENGTH];
 -    struct lgtd_lifx_light_state    state;
--    lgtd_time_mono_t                last_light_state_at;
--    lgtd_time_mono_t                dirty_at;
--    uint16_t                        expected_power_on;
-+    RB_ENTRY(lgtd_lifx_bulb)                link;
-+    SLIST_ENTRY(lgtd_lifx_bulb)             link_by_gw;
-+    lgtd_time_mono_t                        last_light_state_at;
-+    lgtd_time_mono_t                        last_runtime_info_at;
-+    lgtd_time_mono_t                        dirty_at;
-+    uint16_t                                expected_power_on;
-+    uint8_t                                 addr[LGTD_LIFX_ADDR_LENGTH];
-+    struct lgtd_lifx_gateway                *gw;
-+    struct lgtd_lifx_light_state            state;
-+    struct {
-+        lgtd_time_mono_t                    updated_at;
-+        struct lgtd_lifx_ip_state           state;
-+        struct lgtd_lifx_ip_firmware_info   fw_info;
-+    }                                       ips[LGTD_LIFX_BULB_IP_COUNT];
-+    struct lgtd_lifx_product_info           product_info;
-+    struct lgtd_lifx_runtime_info           runtime_info;
+     lgtd_time_mono_t                last_light_state_at;
++    lgtd_time_mono_t                runtime_info_updated_at;
+     lgtd_time_mono_t                dirty_at;
+     uint16_t                        expected_power_on;
++    uint8_t                         addr[LGTD_LIFX_ADDR_LENGTH];
++    struct lgtd_lifx_gateway        *gw;
++    struct lgtd_lifx_light_state    state;
++    struct lgtd_lifx_bulb_ip        ips[LGTD_LIFX_BULB_IP_COUNT];
++    struct lgtd_lifx_product_info   product_info;
++    struct lgtd_lifx_runtime_info   runtime_info;
  };
  RB_HEAD(lgtd_lifx_bulb_map, lgtd_lifx_bulb);
  SLIST_HEAD(lgtd_lifx_bulb_list, lgtd_lifx_bulb);
-@@ -69,3 +110,19 @@
+@@ -69,3 +113,17 @@
                                      lgtd_time_mono_t);
  void lgtd_lifx_bulb_set_power_state(struct lgtd_lifx_bulb *, uint16_t);
  void lgtd_lifx_bulb_set_tags(struct lgtd_lifx_bulb *, uint64_t);
 +
-+void lgtd_lifx_bulb_set_mcu_state(struct lgtd_lifx_bulb *,
-+                                  const struct lgtd_lifx_ip_state *,
-+                                  lgtd_time_mono_t);
-+void lgtd_lifx_bulb_set_mcu_firmware_info(struct lgtd_lifx_bulb *,
-+                                          const struct lgtd_lifx_ip_firmware_info *);
-+void lgtd_lifx_bulb_set_wifi_state(struct lgtd_lifx_bulb *,
-+                                   const struct lgtd_lifx_ip_state *,
-+                                   lgtd_time_mono_t);
-+void lgtd_lifx_bulb_set_wifi_firmware_info(struct lgtd_lifx_bulb *,
-+                                           const struct lgtd_lifx_ip_firmware_info *);
++void lgtd_lifx_bulb_set_ip_state(struct lgtd_lifx_bulb *bulb,
++                                        enum lgtd_lifx_bulb_ips ip_id,
++                                        const struct lgtd_lifx_ip_state *state,
++                                        lgtd_time_mono_t received_at);
++void lgtd_lifx_bulb_set_ip_firmware_info(struct lgtd_lifx_bulb *bulb,
++                                         enum lgtd_lifx_bulb_ips ip_id,
++                                         const struct lgtd_lifx_ip_firmware_info *info,
++                                         lgtd_time_mono_t received_at);
 +void lgtd_lifx_bulb_set_product_info(struct lgtd_lifx_bulb *,
 +                                     const struct lgtd_lifx_product_info *);
 +void lgtd_lifx_bulb_set_runtime_info(struct lgtd_lifx_bulb *,
@@ -521,7 +487,7 @@
  
      int tag_id;
      LGTD_LIFX_WIRE_FOREACH_TAG_ID(tag_id, pkt->tags) {
-@@ -707,3 +695,142 @@
+@@ -707,3 +695,129 @@
  
      lgtd_lifx_bulb_set_tags(b, pkt->tags);
  }
@@ -534,18 +500,15 @@
 +    assert(gw && hdr && pkt);
 +
 +    const char  *type;
-+    void        (*bulb_fn)(struct lgtd_lifx_bulb *,
-+                           const struct lgtd_lifx_ip_state *,
-+                           lgtd_time_mono_t);
-+
++    enum lgtd_lifx_bulb_ips ip_id;
 +    switch (hdr->packet_type) {
 +    case LGTD_LIFX_MESH_INFO:
 +        type = "MCU_STATE";
-+        bulb_fn = lgtd_lifx_bulb_set_mcu_state;
++        ip_id = LGTD_LIFX_BULB_MCU_IP;
 +        break;
 +    case LGTD_LIFX_WIFI_INFO:
 +        type = "WIFI_STATE";
-+        bulb_fn = lgtd_lifx_bulb_set_wifi_state;
++        ip_id = LGTD_LIFX_BULB_WIFI_IP;
 +        break;
 +    default:
 +        lgtd_info("invalid ip state packet_type %#hx", hdr->packet_type);
@@ -562,11 +525,9 @@
 +        pkt->signal_strength, pkt->rx_bytes, pkt->tx_bytes, pkt->reserved
 +    );
 +
-+    LGTD_LIFX_GATEWAY_SET_BULB_ATTR_WITH_RECV_AT(
-+        gw,
-+        hdr->target.device_addr,
-+        bulb_fn,
-+        (const struct lgtd_lifx_ip_state *)pkt
++    LGTD_LIFX_GATEWAY_SET_BULB_ATTR(
++        gw, hdr->target.device_addr, lgtd_lifx_bulb_set_ip_state,
++        ip_id, (const struct lgtd_lifx_ip_state *)pkt, gw->last_pkt_at
 +    );
 +}
 +
@@ -577,18 +538,20 @@
 +{
 +    assert(gw && hdr && pkt);
 +
++    char built_at[64], installed_at[64];
++    LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->built_at, built_at);
++    LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->installed_at, installed_at);
++
 +    const char  *type;
-+    void        (*bulb_fn)(struct lgtd_lifx_bulb *,
-+                           const struct lgtd_lifx_ip_firmware_info *);
-+
++    enum lgtd_lifx_bulb_ips ip_id;
 +    switch (hdr->packet_type) {
 +    case LGTD_LIFX_MESH_FIRMWARE:
 +        type = "MCU_FIRMWARE_INFO";
-+        bulb_fn = lgtd_lifx_bulb_set_mcu_firmware_info;
++        ip_id = LGTD_LIFX_BULB_MCU_IP;
 +        break;
 +    case LGTD_LIFX_WIFI_FIRMWARE_STATE:
 +        type = "WIFI_FIRMWARE_INFO";
-+        bulb_fn = lgtd_lifx_bulb_set_wifi_firmware_info;
++        ip_id = LGTD_LIFX_BULB_WIFI_IP;
 +        break;
 +    default:
 +        lgtd_info("invalid ip firmware packet_type %#hx", hdr->packet_type);
@@ -598,10 +561,6 @@
 +        return;
 +    }
 +
-+    char built_at[64], installed_at[64];
-+    LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->built_at, built_at);
-+    LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->installed_at, installed_at);
-+
 +    lgtd_debug(
 +        "%s <-- [%s]:%hu - %s "
 +        "built_at=%s, installed_at=%s, version=%u",
@@ -610,10 +569,8 @@
 +    );
 +
 +    LGTD_LIFX_GATEWAY_SET_BULB_ATTR(
-+        gw,
-+        hdr->target.device_addr,
-+        bulb_fn,
-+        (const struct lgtd_lifx_ip_firmware_info *)pkt
++        gw, hdr->target.device_addr, lgtd_lifx_bulb_set_ip_firmware_info,
++        ip_id, (const struct lgtd_lifx_ip_firmware_info *)pkt, gw->last_pkt_at
 +    );
 +}
 +
@@ -632,9 +589,7 @@
 +    );
 +
 +    LGTD_LIFX_GATEWAY_SET_BULB_ATTR(
-+        gw,
-+        hdr->target.device_addr,
-+        lgtd_lifx_bulb_set_product_info,
++        gw, hdr->target.device_addr, lgtd_lifx_bulb_set_product_info,
 +        (const struct lgtd_lifx_product_info *)pkt
 +    );
 +}
@@ -657,11 +612,9 @@
 +        device_time, uptime, downtime
 +    );
 +
-+    LGTD_LIFX_GATEWAY_SET_BULB_ATTR_WITH_RECV_AT(
-+        gw,
-+        hdr->target.device_addr,
-+        lgtd_lifx_bulb_set_runtime_info,
-+        (const struct lgtd_lifx_runtime_info *)pkt
++    LGTD_LIFX_GATEWAY_SET_BULB_ATTR(
++        gw, hdr->target.device_addr, lgtd_lifx_bulb_set_runtime_info,
++        (const struct lgtd_lifx_runtime_info *)pkt, gw->last_pkt_at
 +    );
 +}
 diff --git a/lifx/gateway.h b/lifx/gateway.h
@@ -688,26 +641,20 @@
      struct lgtd_lifx_message        pkt_ring[LGTD_LIFX_GATEWAY_PACKET_RING_SIZE];
  #define LGTD_LIFX_GATEWAY_INC_MESSAGE_RING_INDEX(idx)  do { \
      (idx) += 1;                                             \
-@@ -77,6 +84,18 @@
+@@ -77,6 +84,12 @@
  
  extern struct lgtd_lifx_gateway_list lgtd_lifx_gateways;
  
-+#define LGTD_LIFX_GATEWAY_SET_BULB_ATTR(gw, bulb_addr, bulb_fn, payload) do {   \
-+    struct lgtd_lifx_bulb *b;                                                   \
-+    LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, bulb_addr);                     \
-+    (bulb_fn)(b, (payload));                                                    \
-+} while (0)
-+
-+#define LGTD_LIFX_GATEWAY_SET_BULB_ATTR_WITH_RECV_AT(gw, bulb_addr, bulb_fn, payload) do {  \
-+    struct lgtd_lifx_bulb *b;                                                               \
-+    LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, bulb_addr);                                 \
-+    (bulb_fn)(b, (payload), (gw)->last_pkt_at);                                             \
++#define LGTD_LIFX_GATEWAY_SET_BULB_ATTR(gw, bulb_addr, bulb_fn, ...) do {   \
++    struct lgtd_lifx_bulb *b;                                               \
++    LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, bulb_addr);                 \
++    (bulb_fn)(b, __VA_ARGS__);                                              \
 +} while (0)
 +
  struct lgtd_lifx_gateway *lgtd_lifx_gateway_get(const struct sockaddr_storage *);
  struct lgtd_lifx_gateway *lgtd_lifx_gateway_open(const struct sockaddr_storage *,
                                                   ev_socklen_t,
-@@ -119,3 +138,15 @@
+@@ -119,3 +132,15 @@
  void lgtd_lifx_gateway_handle_tags(struct lgtd_lifx_gateway *,
                                     const struct lgtd_lifx_packet_header *,
                                     const struct lgtd_lifx_packet_tags *);
--- a/series	Tue Aug 11 00:37:46 2015 -0700
+++ b/series	Thu Aug 13 02:29:45 2015 -0700
@@ -1,2 +1,3 @@
 use_jq_when_avalaible.patch
+fix_ipv4_address_formatting.patch
 implement_some_metadata_packet_types.patch