Update openHAB Things configuration using Ansible

Posted by ads' corner on Tuesday, 2018-07-03
Posted in [Ansible][Linux][Openhab]

In my earlier openHAB blog posts I automated the installation of extensions and linking of Channels to Items. Another problem I’m facing is the configuration of items. Again, that’s very easy in the UI - if you are willing to click through the list of Items, and manually do all the steps.

Among other things I’m using the binding-yahooweather and the binding-ipp bindings, and the first one needs configuration before it can work properly. For the second one, it righly discovered a laser printer in our network, but occasionally when openHAB requests the status information, this spins up an internal disk in the printer. Therefore it is feasible to increase the time between checks - it’s just the number of outstanding print jobs anyway. Doesn’t matter if someone reacts 5 or 15 minutes later, if the problem was not discovered instantly.

The configuration is available in the list of Things, and that is also the place used to update the config. However that’s only valid for “version 2” Things, not for legacy Things. The legacy ones are configured using files.

Let’s first fetch a list of available Things:

1
2
3
4
5
- name: Get things
  uri:
    url: "http://{{ ansible_host }}:8080/rest/things"
  register: o2_things
  changed_when: false

Configuration is per Channel, therefore loop over them:

1
2
3
4
5
  with_subelements:
    - "{{ o2_things.json }}"
    - channels
  loop_control:
    label: "{{ item.0.thingTypeUID }} - {{ item.1.channelTypeUID }} - {{ item.0.UID }}"

The tricky part for the configuration is that each Channel has a different configuration, and needs different keys and values. That is not straightforward, and can’t easily be automated in a way which covers all Items in one single Ansible Play. But it’s still possible to have one Play per type of Item.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- name: Update weather information
  uri:
    url: "{{ o2_things.url }}/{{ item.0.UID | urlencode }}/config"
    body: "{ \"location\"{{':'}} {{ weather_woeid }}, \"refresh\"{{':'}} {{ weather_refresh }} }"
    body_format: json
    method: PUT
  when: item.0.thingTypeUID == "yahooweather:weather" and (item.0.configuration.location != weather_woeid or item.0.configuration.refresh != weather_refresh)
  with_subelements:
    - "{{ o2_things.json }}"
    - channels
  loop_control:
    label: "{{ item.0.thingTypeUID }} - {{ item.1.channelTypeUID }} - {{ item.0.UID }}"

- name: Update printer configuration
{{':'}} \"{{ item.0.configuration.url }}\" }"
  uri:
    url: "{{ o2_things.url }}/{{ item.0.UID | urlencode }}/config"
    body: "{ \"name\"{{':'}} \"{{ item.0.configuration.name }}\", \"refresh\"{{':'}} {{ printer_refresh }}, \"url\"{{':'}} \"{{ item.0.configuration.url }}\" }"
    body_format: json
    method: PUT
  when: item.0.thingTypeUID == "ipp:printer" and item.0.configuration.refresh != printer_refresh
  with_subelements:
    - "{{ o2_things.json }}"
    - channels
  loop_control:
    label: "{{ item.0.thingTypeUID }} - {{ item.1.channelTypeUID }} - {{ item.0.UID }}"

The first Play updates the weather configuration, increases the check interval to 15 minutes (900 seconds) in my case (defined in $weather_refresh), and set’s the location for the weather. This is a number which can be looked up using this website.

The second Play updates the printer configuration, and sets the check interval to 15 minutes (900 seconds) in my case (defined in $printer_refresh).

If you update the configuration, make sure you include the same elements which are already in the Channel/Item configuration. The entire configuration is updated, not just the parts which are specified in the PUT request. The second Play works around this problem by inserting existing values into the configuration again.

The configuration must be valid JSON, and a matching header is added to the request by using the body_format: json option.

Last but not least, the current configuration can be extracted and viewed using curl and the REST API:

1
curl -s -X GET --header "Accept: application/json" "http://127.0.0.1:8080/rest/things" | jq '.' | less

Categories: [Ansible] [Linux] [Openhab]