2019/11/11

Zigbee Lighting - Sylvania 74099 4/8 button remote will not pair.


https://community.hubitat.com/t/sylvania-lightify-smart-switch-8-functions-4-buttons/10943

Update:

Ken Fraleigh from the Hubitat community pointed out that what I thought of as "Reset" (3-4) is actually the ZLL (Zigbee Light Link). This information came from the European Sylvania site where they have been discussion support for ZB 3.0 and Hue Bridge compatibility.


So I was reading through the threads above and others trying to get the Sylvania  4 button controller working with the Lightify Hub . We have a goal of keeping this cost effective, shopping for deals. Maybe Hubitat for x-mas,

Anyway while trying to get one re-paired was thinking back to another one I had and was sitting on the shelf waiting to go back. The Device has 4 buttons

12
34

The Manual and on-screen directions tell you to press 2 & 3 and hold for 2 seconds and it should pulse orange and re-pair.

So that's not working, I should have realized at this point that the 2 button isn't flashing. This is because I dropped onto the floor and it exploded like an old cell with removable battery parts going flying. Wish I had thought of this earlier, but that's ok.

So if 2-3 does something, what else exists ?

3 & 4: While held, flashes orange and then ends with red. (ZLL Pairing)
1 & 4: After a few seconds flashes green 10 times then ends with long green

1 & 4 We'll call power-on reboot. It's similar to what happens when you pull the tab keeping the battery from making contact.

3 & 4 Feels like some kind of reset, warning orange ending with Red. I was incorrect this is ZLL Pairing mode (Thanks Ken)

So back to the story, This was 1 of 2 I'd just gotten, 1 new and one as replacement for another which got paired to a system that was shipped back and couldn't get it paired to the Lightify. 

After I disassembled/reassembled the other one, and had re-paired it by pressing on the metal buttons to get it paired. If you have any question if your actually pressing 2 & 3, I'd recommend removing the face and checking out under the hood.To remove the front bezel, remove the battery cover and in the rounded corners you'll see the two plastic hook tabs holding the bezel in-place.

I unpacked the one destined to be returned and did the following:

Reboot:1 & 4
ZHA Pair:2 & 3
Reset
ZLL Pairing:
3 & 4

And look at that, it paired right up. 

Sylvania why didn't you just say that. Searched the site, Submitted tickets, Marketing-Speak back, no tech support.




2018/12/04

Mapping Private/Public Docker ports with AWS ECS and Docker Net=Bridge

I've done many searches trying to find a way to know what the public port numbers that have been assigned to my docker container are from inside the container. Docker has a way to query this information but that means exposing the Docker Daemon interface (socket or tcp) to the process running inside the container and sadly there are little security controls around that so understandably most are reluctant to expose that interface inside the container

Amazon's ECS agent has a lightweight which will expose details about the container which happens to include the Private/Public port mappings. I've included a link to the script I wrote here GitHub Gist along with the code below.

It requires the use of JQ which I happen to consider a fundamental tool if your going to manipulate JSON files from within bash.




2018/08/23

Testing for data types in Jinja Templates

Writing templates for Jinja is an artform all of its very own. Jinja is the Python variant of the HandleBars templater that combines Python code styling with Mustache templating from Java.

Some Background on Jinja

Jinja allows loops, conditionals and a very Unix/Shell like ability to pipe the contents of variables from function/filter to the next to evaluate and transform variables. One of the simplest forms that helps to explain the syntax is

{{ variable | default("variable had no value") }}

In the above case, the value defined by variable is piped to the default filter after the pipe. The default filter does what it's name implies, if the value passed is None or Undefined it applies the passed arg as the return.

There are many other good examples of Jinja filters and loops so I'm not going to try to cover that material here.

Testing Types in Jinja

In order to create templates that are not brittle and fail in unexpected ways testing that variables are as expected before getting into more complex code is always advisable. A simple precaution might look like

{% for value in python_list | default([]) %}
{{ value }}
{% endfor %}


As you can see from the example above and combining it with knowledge about default you can see that the loop executes and in the event python_list is undefined the for statement is protected against failure since an empty list will be substituted for the undefined.

The issue is how to protect against other data types, if python_list was a dictionary how would this behave, or any other python type.

Jinja includes some type tests, but they sometimes are simple as but the creators of the Jinja typing were apparently thinking about language independent tests when they created them. A great resource for Jinja filters is https://www.webforefront.com/django/usebuiltinjinjafilters.html which discusses the primates

'is string' (definitive)
'is mapping' (definitive)
'is number' (non-definitive)
'is iterable' (overloaded)
'is sequence' (overloaded)
'is sameas' (tests inheritance)

As a result of the non-deterministic nature of the tests described above a bit more logic must be applied to determine Python types if you want to use the Jinja filters (vs in-line python)

Below are the best conditionals I've found to type an element, tho if you were to structure it as a If/Then style case block you can simplify the tests a bit because of precedence. These are meant to be stand-alone "fully-qualified" tests.

Testing for Strings

Testing for strings is the singular simple test with Jinja without the need for any additional conditionals to be used. All string objects are 'is string' and non-strings are 'not is string'

{% if value is string %}
{{ value }} is a string
{% endif %}


The complication starts because a string "is string" also tests positive as "is sequence" and "is iterable" because a string is a list of bytes that python treats as both an array string[0] and a simple variable

What's missing from the filters are items like "is boolean" "is list" and "is dict".

Testing for a Dict

Testing for Dictionary objects is also simplified since they are the only type i'm aware of that tests true for 'is mapping'

{% if value is mapping %}
{{ value }} is a mapping
{% endif %}

Testing for a Boolean

Testing for a Boolean is a bit more complex, since technically a Boolean is also a number (and Boolean's test truthy for 'is number'). It turns out that any Boolean will test 'is sameas' for its own state so:

{% if value is sameas true or value is sameas false %}
{{ value }} is a boolean
{% endif %}


Satisfies the test for a boolean

Testing for a Number

Testing for a Number should be straight-forward 'is number' but since as discussed above since Boolean's test true for 'is number' the true test of a number is expressed as "is number and not is boolean"

{% if value is number and value is not sameas true and value is not sameas false %}
{{ value }} is a boolean
{% endif %}


Satisfies the test for a number

Testing for a List

Lastly, testing for a list is a compound conditional since lists are both sequences and iterable but are not mappings or strings. So to test for a list the proper representation looks like



{% if value is sequence and value is not mapping and value is not string %}
{{ value }} is a list
{% endif %}

Summary and Example Code

Below is python code demonstrating the above principles in an easy to replicate manner. OrderedDict is used to produce results in a repeatable manner, it was not necessary.


import yaml
from collections import OrderedDict
from jinja2 import Template as Jinja_Template

sample_data = """
  a: 1
  b: one
  c: "2"
  d: "three"
  e:
    - 1
    - 2
    - 3
  f:
    one: test
    two: further testing
    3: even more testing
  g: True
  h: False
"""

sample_template = """
Testing Jinja Types
{%- for key,value in sample_data.items() %}
  Processing {{key}}={{value}}
  {% if value is sameas true %} is True{% endif -%} 
  {% if value is sameas false %} is False{% endif -%} 
  {% if value is number %} is number{% endif -%} 
  {% if value is mapping %} is mapping{% endif -%} 
  {% if value is sequence %} is sequence{% endif -%} 
  {% if value is iterable %} is iterable{% endif -%} 
  {% if value is string %} is string{% endif -%} 
{% endfor %}

Testing Python Types
{%- for key,value in sample_data.items() %}
  Processing {{key}}={{value}}
  {% if value is string %} its a String{% endif -%}
  {% if value is mapping %} its a Dict{% endif -%}
  {% if value is sameas true or value is sameas false %} its a Boolean{% endif -%}
  {% if value is number and value is not sameas true and value is not sameas false%} its a Number{% endif -%}
  {% if value is sequence and value is not mapping and value is not string %} its a List{% endif -%}
{% endfor %}
"""

sample_data = yaml.load(sample_data)
print(yaml.dump(sample_data, default_flow_style=False))

sample_data = OrderedDict( sorted(sample_data.items(), key=lambda x: x[0]) )
templater = Jinja_Template(sample_template)
print(templater.render(sample_data=sample_data))

Output from the above:

Testing Jinja Types
  Processing a=1
    is number
  Processing b=one
    is sequence is iterable is string
  Processing c=2
    is sequence is iterable is string
  Processing d=three
    is sequence is iterable is string
  Processing e=[1, 2, 3]
    is sequence is iterable
  Processing f={3: 'even more testing', 'two': 'further testing', 'one': 'test'}
    is mapping is sequence is iterable
  Processing g=True
    is True is number
  Processing h=False
    is False is number

Testing Python Types
  Processing a=1
    its a Number
  Processing b=one
    its a String
  Processing c=2
    its a String
  Processing d=three
    its a String
  Processing e=[1, 2, 3]
    its a List
  Processing f={3: 'even more testing', 'two': 'further testing', 'one': 'test'}
    its a Dict
  Processing g=True
    its a Boolean
  Processing h=False
    its a Boolean