changeset 407:554a26aaa1df

wip
author Louis Opter <kalessin@kalessin.fr>
date Tue, 29 Dec 2015 14:43:27 +0100
parents 20b1e7862d25
children 28915b460db7
files add_power_transition.patch
diffstat 1 files changed, 265 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/add_power_transition.patch	Mon Dec 28 18:44:51 2015 +0100
+++ b/add_power_transition.patch	Tue Dec 29 14:43:27 2015 +0100
@@ -58,7 +58,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/core/effect.c
-@@ -0,0 +1,145 @@
+@@ -0,0 +1,171 @@
 +// Copyright (c) 2015, Louis Opter <kalessin@kalessin.fr>
 +//
 +// This file is part of lighstd.
@@ -92,6 +92,7 @@
 +#include "lifx/wire_proto.h"
 +#include "proto.h"
 +#include "effect.h"
++#include "lightsd.h"
 +
 +struct lgtd_effect_list lgtd_effects = LIST_HEAD_INITIALIZER(&lgtd_effects);
 +
@@ -100,6 +101,7 @@
 +{
 +    assert(effect);
 +
++    lgtd_info("ending effect %s, id=%p", effect->name, effect);
 +    LIST_REMOVE(effect, link);
 +    if (effect->timer) {
 +        lgtd_timer_stop(effect->timer);
@@ -130,27 +132,42 @@
 +        lgtd_time_mono_t diff = now - effect->created_at + effect->duration;
 +        // maybe the computer was sleepy
 +        if (diff > LGTD_EFFECT_STALE_THRESHOLD_MSECS) {
++            lgtd_warnx(
++                "stopping stale effect %s created %jums ago, id=%p, "
++                "duration=%dms",
++                effect->name, (uintmax_t)diff, effect, effect->duration
++            );
 +            lgtd_effect_stop(effect);
 +            return;
 +        }
 +    }
 +
 +    effect->apply_cb(effect);
++    effect->apply_cnt++;
 +}
 +
 +struct lgtd_effect *
-+lgtd_effect_start(int duration,
++lgtd_effect_start(const char *name,
++                  int duration,
 +                  void (*duration_cb)(const struct lgtd_effect *),
 +                  int timer_flags,
 +                  int timer_ms,
 +                  void (*apply_cb)(const struct lgtd_effect *),
 +                  union lgtd_effect_ctx ctx)
 +{
++    assert(name);
++    assert(timer_ms >= 0);
++    assert(timer_ms < duration);
++    if (timer_ms) {
++        assert(apply_cb);
++    }
++
 +    struct lgtd_effect *effect = calloc(1, sizeof(*effect));
 +    if (!effect) {
 +        return NULL;
 +    }
 +
++    effect->name = name;
 +    effect->created_at = lgtd_time_monotonic_msecs();
 +    effect->duration = duration;
 +    effect->duration_cb = duration_cb;
@@ -180,8 +197,17 @@
 +        if (!effect->timer) {
 +            goto err;
 +        }
++        lgtd_info(
++            "starting effect %s, id=%p, duration=%dms, tick=%dms",
++            name, effect, duration, timer_ms
++        );
 +    } else {
-+        effect->apply_cb(effect);
++        lgtd_info(
++            "starting effect %s, id=%p, duration=%dms", name, effect, duration
++        );
++        if (effect->apply_cb) {
++            effect->apply_cb(effect);
++        }
 +    }
 +
 +    return effect;
@@ -208,7 +234,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/core/effect.h
-@@ -0,0 +1,53 @@
+@@ -0,0 +1,56 @@
 +// Copyright (c) 2015, Louis Opter <kalessin@kalessin.fr>
 +//
 +// This file is part of lighstd.
@@ -237,11 +263,13 @@
 +
 +struct lgtd_effect {
 +    LIST_ENTRY(lgtd_effect)         link;
++    const char                      *name;
 +    lgtd_time_mono_t                created_at;
 +    int                             duration;
 +    void                            (*duration_cb)(const struct lgtd_effect *);
 +    struct lgtd_timer               *timer;
 +    void                            (*apply_cb)(const struct lgtd_effect *);
++    uint32_t                        apply_cnt;
 +    union lgtd_effect_ctx           ctx;
 +};
 +LIST_HEAD(lgtd_effect_list, lgtd_effect);
@@ -254,7 +282,8 @@
 +    return (uintptr_t)effect;
 +}
 +
-+struct lgtd_effect *lgtd_effect_start(int, // duration
++struct lgtd_effect *lgtd_effect_start(const char *,
++                                      int, // duration
 +                                      void (*)(const struct lgtd_effect *), // duration cb
 +                                      int, // timer flags
 +                                      int, // timer ms
@@ -504,15 +533,35 @@
              false
          ),
          LGTD_JSONRPC_NODE(
-@@ -1103,7 +1169,7 @@
+@@ -1103,23 +1169,23 @@
  {
      static const struct lgtd_jsonrpc_method methods[] = {
          LGTD_JSONRPC_METHOD(
 -            "power_on", 1, // t
-+            "power_on", 2, // t
++            "power_on", 2, // t, [transition]
              lgtd_jsonrpc_check_and_call_power_on
          ),
          LGTD_JSONRPC_METHOD(
+-            "power_off", 1, // t
++            "power_off", 2, // t, [transition]
+             lgtd_jsonrpc_check_and_call_power_off
+         ),
+         LGTD_JSONRPC_METHOD(
+-            "power_toggle", 1, // t
++            "power_toggle", 2, // t, [transition]
+             lgtd_jsonrpc_check_and_call_power_toggle
+         ),
+         LGTD_JSONRPC_METHOD(
+-            "set_light_from_hsbk", 6, // t, h, s, b, k, t
++            "set_light_from_hsbk", 6, // t, h, s, b, k, [transition]
+             lgtd_jsonrpc_check_and_call_set_light_from_hsbk
+         ),
+         LGTD_JSONRPC_METHOD(
+-            // t, waveform, h, s, b, k, period, cycles, skew_ratio, transient
++            // t, waveform, h, s, b, k, period, cycles, skew_ratio, [transient]
+             "set_waveform", 10,
+             lgtd_jsonrpc_check_and_call_set_waveform
+         ),
 diff --git a/core/lightsd.c b/core/lightsd.c
 --- a/core/lightsd.c
 +++ b/core/lightsd.c
@@ -558,7 +607,7 @@
  #include "router.h"
  #include "lightsd.h"
  
-@@ -58,23 +59,47 @@
+@@ -58,23 +59,68 @@
      }
  }
  
@@ -599,6 +648,27 @@
 +    }
 +
 +    SEND_RESULT(client, ok);
++}
++
++void
++lgtd_proto_power_off(struct lgtd_client *client,
++                     const struct lgtd_proto_target_list *targets,
++                     int transition)
++{
++    assert(targets);
++    assert(transition >= 0);
++
++    bool ok;
++    if (transition) {
++        ok = lgtd_effect_power_transition(
++            targets, LGTD_EFFECT_POWER_TRANSITION_OFF, transition
++        );
++    } else {
++        struct lgtd_lifx_packet_power pkt = { .power = LGTD_LIFX_POWER_OFF };
++        ok = lgtd_router_send(targets, LGTD_LIFX_SET_POWER_STATE, &pkt);
++    }
++
++    SEND_RESULT(client, ok);
  }
  
  void
@@ -612,7 +682,7 @@
  
      struct lgtd_router_device_list *devices = NULL;
      devices = lgtd_router_targets_to_devices(targets);
-@@ -85,30 +110,80 @@
+@@ -85,33 +131,58 @@
          return;
      }
  
@@ -673,36 +743,21 @@
  }
  
  void
- lgtd_proto_power_off(struct lgtd_client *client,
+-lgtd_proto_power_off(struct lgtd_client *client,
 -                     const struct lgtd_proto_target_list *targets)
-+                     const struct lgtd_proto_target_list *targets,
-+                     int transition)
- {
-     assert(targets);
-+    assert(transition >= 0);
- 
+-{
+-    assert(targets);
+-
 -    struct lgtd_lifx_packet_power_state pkt = { .power = LGTD_LIFX_POWER_OFF };
 -    SEND_RESULT(
 -        client, lgtd_router_send(targets, LGTD_LIFX_SET_POWER_STATE, &pkt)
 -    );
-+    if (transition) {
-+        return;
-+    }
-+
-+    bool ok;
-+    if (transition) {
-+        ok = lgtd_effect_power_transition(
-+            targets, LGTD_EFFECT_POWER_TRANSITION_OFF, transition
-+        );
-+    } else {
-+        struct lgtd_lifx_packet_power pkt = { .power = LGTD_LIFX_POWER_OFF };
-+        ok = lgtd_router_send(targets, LGTD_LIFX_SET_POWER, &pkt);
-+    }
-+
-+    SEND_RESULT(client, ok);
- }
- 
- void
+-}
+-
+-void
+ lgtd_proto_set_light_from_hsbk(struct lgtd_client *client,
+                                const struct lgtd_proto_target_list *targets,
+                                int hue,
 diff --git a/core/proto.h b/core/proto.h
 --- a/core/proto.h
 +++ b/core/proto.h
@@ -736,6 +791,18 @@
  void lgtd_proto_get_light_state(struct lgtd_client *, const struct lgtd_proto_target_list *);
  void lgtd_proto_tag(struct lgtd_client *, const struct lgtd_proto_target_list *, const char *);
  void lgtd_proto_untag(struct lgtd_client *, const struct lgtd_proto_target_list *, const char *);
+diff --git a/core/router.h b/core/router.h
+--- a/core/router.h
++++ b/core/router.h
+@@ -17,6 +17,8 @@
+ 
+ #pragma once
+ 
++struct lgtd_lifx_tag;
++
+ // TODO: return that from the functions in there and handle it:
+ enum lgtd_router_error {
+     LGTD_ROUTER_INVALID_TARGET_ERROR,
 diff --git a/core/utils.c b/core/utils.c
 --- a/core/utils.c
 +++ b/core/utils.c
@@ -813,7 +880,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/effects/power_transition.c
-@@ -0,0 +1,202 @@
+@@ -0,0 +1,305 @@
 +// Copyright (c) 2015, Louis Opter <kalessin@kalessin.fr>
 +//
 +// This file is part of lighstd.
@@ -857,7 +924,8 @@
 +#include "power_transition.h"
 +
 +static void
-+lgtd_effect_power_transition_clear_target_list(struct lgtd_effect_power_transition_target_list *targets)
++lgtd_effect_power_transition_clear_target_list(
++                    struct lgtd_effect_power_transition_target_list *targets)
 +{
 +    assert(targets);
 +
@@ -869,8 +937,26 @@
 +    }
 +}
 +
++static struct lgtd_lifx_bulb *
++lgtd_effect_power_transition_off_possibly_get_bulb(uint8_t *device_id)
++{
++    assert(device_id);
++
++    struct lgtd_lifx_bulb *bulb = lgtd_lifx_bulb_get(device_id);
++    if (!bulb) {
++        char addr[LGTD_LIFX_ADDR_LENGTH];
++        LGTD_IEEE8023MACTOA(bulb->addr, addr);
++        lgtd_warn(
++            "bulb %s is unavailable: can't restore its original brightness "
++            "at the end of a power_off transition", addr
++        );
++    }
++    return bulb;
++}
++
 +static void
-+lgtd_effect_power_transition_off_duration_callback(const struct lgtd_effect *effect)
++lgtd_effect_power_transition_off_duration_callback(
++                    const struct lgtd_effect *effect)
 +{
 +    assert(effect);
 +
@@ -878,20 +964,10 @@
 +
 +    struct lgtd_effect_power_transition_target *target;
 +    SLIST_FOREACH(target, &ctx->targets, link) {
-+        struct lgtd_lifx_bulb *bulb = lgtd_lifx_bulb_get(target->device_id);
-+        if (!bulb) {
-+            char addr[LGTD_LIFX_ADDR_LENGTH];
-+            LGTD_IEEE8023MACTOA(bulb->addr, addr);
-+            lgtd_warn(
-+                "bulb %s is unavailable: can't restore its original brightness "
-+                "after a power transition", addr
-+            );
-+        } else { // restore the original brightness
-+            struct lgtd_lifx_packet_power pkt_power = {
-+                .power = LGTD_LIFX_POWER_OFF
-+            };
-+            lgtd_router_send_to_device(bulb, LGTD_LIFX_SET_POWER, &pkt_power);
-+
++        struct lgtd_lifx_bulb *bulb;
++        uint8_t *device_id = target->device_id;
++        bulb = lgtd_effect_power_transition_off_possibly_get_bulb(device_id);
++        if (bulb) { // restore the original brightness
 +            struct lgtd_lifx_packet_light_color pkt_light_color = {
 +                .hue = bulb->state.hue,
 +                .saturation = bulb->state.saturation,
@@ -910,6 +986,79 @@
 +}
 +
 +static void
++lgtd_effect_power_transition_off_set_brightness_to_zero(
++                    struct lgtd_effect_power_transition_target_list *targets,
++                    int duration)
++{
++    assert(targets);
++
++    struct lgtd_effect_power_transition_target *target;
++    SLIST_FOREACH(target, targets, link) {
++        // we're using LGTD_TIMER_ACTIVATE_NOW so we'll go through the event
++        // loop again which means we must check that the bulb is still there,
++        // even though this is gonna be executed right away to avoid any race
++        // condition:
++        struct lgtd_lifx_bulb *bulb;
++        uint8_t *device_id = target->device_id;
++        bulb = lgtd_effect_power_transition_off_possibly_get_bulb(device_id);
++        struct lgtd_lifx_packet_light_color pkt = {
++            .hue = bulb->state.hue,
++            .saturation = bulb->state.saturation,
++            .brightness = 0,
++            .kelvin = bulb->state.kelvin,
++            .transition = duration
++        };
++        lgtd_lifx_wire_encode_light_color(&pkt);
++        lgtd_router_send_to_device(bulb, LGTD_LIFX_SET_LIGHT_COLOR, &pkt);
++    }
++}
++
++static void
++lgtd_effect_power_transition_off_power_off(
++                    struct lgtd_effect_power_transition_target_list *targets)
++{
++    assert(targets);
++
++    struct lgtd_effect_power_transition_target *target;
++    SLIST_FOREACH(target, targets, link) {
++        struct lgtd_lifx_bulb *bulb;
++        uint8_t *device_id = target->device_id;
++        bulb = lgtd_effect_power_transition_off_possibly_get_bulb(device_id);
++        if (bulb) {
++            struct lgtd_lifx_packet_power pkt = {
++                .power = LGTD_LIFX_POWER_OFF
++            };
++            lgtd_router_send_to_device(bulb, LGTD_LIFX_SET_POWER_STATE, &pkt);
++        }
++    }
++}
++
++static void
++lgtd_effect_power_transition_off_apply_callback(const struct lgtd_effect *effect)
++{
++    assert(effect);
++
++    struct lgtd_effect_power_transition_ctx *ctx = effect->ctx.as_ptr;
++
++    switch (effect->apply_cnt) {
++    case 0:
++        lgtd_effect_power_transition_off_set_brightness_to_zero(
++            &ctx->targets, effect->duration
++        );
++        break;
++    case 1:
++        lgtd_effect_power_transition_off_power_off(&ctx->targets);
++        break;
++    default:
++#ifndef NDEBUG
++        lgtd_warnx("%s called with apply_cnt=%d", __func__, effect->apply_cnt);
++        abort();
++#endif
++        break;
++    }
++}
++
++static void
 +lgtd_effect_power_transition_on_apply_callback(const struct lgtd_effect *effect)
 +{
 +    assert(effect);
@@ -920,6 +1069,11 @@
 +    SLIST_FOREACH(target, &ctx->targets, link) {
 +        struct lgtd_lifx_bulb *bulb = lgtd_lifx_bulb_get(target->device_id);
 +        assert(bulb);
++
++        if (bulb->state.power) {
++            continue; // skip the bulb since it's already on
++        }
++
 +        struct lgtd_lifx_packet_light_color pkt_set_brightness_to_zero = {
 +            .hue = bulb->state.hue,
 +            .saturation = bulb->state.saturation,
@@ -934,7 +1088,9 @@
 +        struct lgtd_lifx_packet_power pkt_power_on = {
 +            .power = LGTD_LIFX_POWER_ON
 +        };
-+        lgtd_router_send_to_device(bulb, LGTD_LIFX_SET_POWER, &pkt_power_on);
++        lgtd_router_send_to_device(
++            bulb, LGTD_LIFX_SET_POWER_STATE, &pkt_power_on
++        );
 +
 +        struct lgtd_lifx_packet_light_color pkt_fade_out = {
 +            .hue = bulb->state.hue,
@@ -961,13 +1117,14 @@
 +    assert(targets);
 +    assert(duration >= 0);
 +
++    struct lgtd_effect_power_transition_ctx *ctx = NULL;
 +    struct lgtd_router_device_list *devices = NULL;
++
 +    devices = lgtd_router_targets_to_devices(targets);
 +    if (!devices) {
 +        goto error;
 +    }
 +
-+    struct lgtd_effect_power_transition_ctx *ctx;
 +    ctx = calloc(1, sizeof(*ctx));
 +    if (!ctx) {
 +        goto error;
@@ -992,35 +1149,48 @@
 +    }
 +    free(devices);
 +
++    const char *name = NULL;
 +    void (*duration_cb)(const struct lgtd_effect *) = NULL;
++    int timer_flags = 0, timer_ms = 0;
 +    void (*apply_cb)(const struct lgtd_effect *) = NULL;
 +    if (state == LGTD_EFFECT_POWER_TRANSITION_OFF) {
++        name = "power_transition[off]";
++        apply_cb = lgtd_effect_power_transition_off_apply_callback;
++        timer_flags = LGTD_TIMER_ACTIVATE_NOW|LGTD_TIMER_PERSISTENT;
++        timer_ms = duration;
++        duration +=
++            LGTD_EFFECT_POWER_TRANSITION_OFF_RESTORE_LIGHT_COLOR_DELAY_MSECS;
 +        duration_cb = lgtd_effect_power_transition_off_duration_callback;
 +    } else {
++        name = "power_transition[on]";
 +        apply_cb = lgtd_effect_power_transition_on_apply_callback;
 +    }
 +    union lgtd_effect_ctx effect_ctx = { .as_ptr = ctx };
 +    const struct lgtd_effect *effect = lgtd_effect_start(
-+        duration, duration_cb, 0, 0, apply_cb, effect_ctx
++        name, duration, duration_cb, timer_flags, timer_ms, apply_cb, effect_ctx
 +    );
 +    if (effect) {
 +        return effect;
 +    }
 +
 +error:
-+    lgtd_warn("can't start a power transition");
++    lgtd_warn(
++        "can't start effect power_transition[%s]",
++        state == LGTD_EFFECT_POWER_TRANSITION_OFF ? "off" : "on"
++    );
 +    if (ctx) {
 +        lgtd_effect_power_transition_clear_target_list(&ctx->targets);
 +    }
 +    if (devices) {
 +        lgtd_router_device_list_free(devices);
 +    }
++    return NULL;
 +}
 diff --git a/effects/power_transition.h b/effects/power_transition.h
 new file mode 100644
 --- /dev/null
 +++ b/effects/power_transition.h
-@@ -0,0 +1,42 @@
+@@ -0,0 +1,48 @@
 +// Copyright (c) 2015, Louis Opter <kalessin@kalessin.fr>
 +//
 +// This file is part of lighstd.
@@ -1045,6 +1215,12 @@
 +    LGTD_EFFECT_POWER_TRANSITION_ON,
 +};
 +
++// if you power off a bulb and set its color right away you'll see the bulb
++// flicker, so let's delay the restore for a bit once the transition is done:
++enum {
++    LGTD_EFFECT_POWER_TRANSITION_OFF_RESTORE_LIGHT_COLOR_DELAY_MSECS = 300
++};
++
 +struct lgtd_effect_power_transition_target {
 +    SLIST_ENTRY(lgtd_effect_power_transition_target)    link;
 +    uint8_t                                             device_id[LGTD_LIFX_ADDR_LENGTH];
@@ -1066,33 +1242,49 @@
 diff --git a/examples/lightsc.py b/examples/lightsc.py
 --- a/examples/lightsc.py
 +++ b/examples/lightsc.py
-@@ -168,13 +168,15 @@
+@@ -75,6 +75,7 @@
+         }
+ 
+     def _execute_payload(self, payload):
++        print(payload)
+         self._socket.send(json.dumps(payload).encode("utf-8"))
+         # FIXME: proper read loop
+         response = self._socket.recv(64 * 1024).decode("utf-8")
+@@ -168,14 +169,17 @@
              transient=transient
          )
  
 -    def power_on(self, target):
+-        return self._jsonrpc_call("power_on", {"target": target})
 +    def power_on(self, target, transition=None):
-+        if transition:
-+            return self._jsonrpc_call("power_on", [target, transition])
-         return self._jsonrpc_call("power_on", {"target": target})
++        args = [target] + ([transition] if transition is not None else [])
++        return self._jsonrpc_call("power_on", args)
  
 -    def power_off(self, target):
+-        return self._jsonrpc_call("power_off", {"target": target})
 +    def power_off(self, target, transition=None):
-         return self._jsonrpc_call("power_off", {"target": target})
++        args = [target] + ([transition] if transition is not None else [])
++        return self._jsonrpc_call("power_off", args)
  
 -    def power_toggle(self, target):
+-        return self._jsonrpc_call("power_toggle", {"target": target})
 +    def power_toggle(self, target, transition=None):
-         return self._jsonrpc_call("power_toggle", {"target": target})
++        args = [target] + ([transition] if transition is not None else [])
++        return self._jsonrpc_call("power_toggle", args)
  
      def get_light_state(self, target):
+         return self._jsonrpc_call("get_light_state", [target])
 diff --git a/lifx/wire_proto.c b/lifx/wire_proto.c
 --- a/lifx/wire_proto.c
 +++ b/lifx/wire_proto.c
-@@ -205,6 +205,21 @@
+@@ -205,6 +205,24 @@
          },
          {
              REQUEST_ONLY,
-+            .name = "SET_POWER", // like SET_POWER_STATE but with transition support
++            // like SET_POWER_STATE but with transition support, not supported
++            // by the earliest versions of the bulbs (Original 1000 fw 1.5 has
++            // it, I don't know which version between 1.1 and 1.5 added it):
++            .name = "SET_POWER",
 +            .type = LGTD_LIFX_SET_POWER,
 +            .size = sizeof(struct lgtd_lifx_packet_power),
 +            .encode = ENCODER(lgtd_lifx_wire_encode_power)
@@ -1110,7 +1302,7 @@
              .name = "SET_TAGS",
              .type = LGTD_LIFX_SET_TAGS,
              .size = sizeof(struct lgtd_lifx_packet_tags),
-@@ -559,16 +574,6 @@
+@@ -559,16 +577,6 @@
          },
          {
              UNIMPLEMENTED,
@@ -1127,25 +1319,26 @@
              .name = "SET_WAVEFORM_OPTIONAL",
              .type = LGTD_LIFX_SET_WAVEFORM_OPTIONAL
          },
-@@ -941,8 +946,6 @@
+@@ -941,8 +949,7 @@
      pkt->brightness = le16toh(pkt->brightness);
      pkt->kelvin = le16toh(pkt->kelvin);
      pkt->dim = le16toh(pkt->dim);
 -    // The bulbs actually return power values between 0 and 0xffff, not sure
 -    // what the intermediate values mean, let's pull them down to 0:
++    // see comment in lgtd_lifx_wire_decode_power_state:
      if (pkt->power != LGTD_LIFX_POWER_ON) {
          pkt->power = LGTD_LIFX_POWER_OFF;
      }
-@@ -954,12 +957,26 @@
+@@ -954,12 +961,26 @@
  {
      assert(pkt);
  
-+    // StatePower does uses the full 0-65535 range, and its value isn't related
++    // POWER_STATE does uses the full 0-65535 range and its value isn't related
 +    // to the brightness or the power level, but is instead related to the
-+    // transition in SetPower: if you do SetPower with a 4s transition at t 0s
-+    // StatePower will be 0 at t 2s StatePower will be 32767 and at t 4s
-+    // StatePower will be 65535 not matter what the targeted brightness is.
-+    // See https://github.com/lopter/lightsd/issues/5
++    // transition in SET_POWER: if you do SET_POWER with a 4s transition at t 0s
++    // POWER_STATE will be 0 at t 2s StatePower will be 32767 and at t 4s
++    // POWER_STATE will be 65535 not matter what the targeted brightness is.
++    // See GH-5: https://github.com/lopter/lightsd/issues/5
      if (pkt->power != LGTD_LIFX_POWER_ON) {
          pkt->power = LGTD_LIFX_POWER_OFF;
      }