Tedee Lock - open and close

Description

This template rule enables OH to open and close the Tedee lock via Tedee bridge.
It needs two switch items for closing and opening, which should reset to OFF by Meta data - expire time 2 s.
Properties :
IP of bridge : “192.168.1.23”
API Token : “12dFd4gD3DqQ” out of the Tedee app
Lock ID : “45666” out of the Tedee app
Mode : “3” - lock only opens without additional pull spring
“4” - lock opens incl. pull spring

If there is no wifi available or the Tedee bridge is disconnected, you will get one of these error messages in the log

[ERROR] [enhab.core.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.ExecutionException: java.net.SocketTimeoutException: Connect Timeout
[ERROR] [enhab.core.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.ExecutionException: java.net.ConnectException: Connection refused

If Tedee operation was successful, you will get no reply from the lock.
If you repeat the same request twice, the lock will answer

[INFO ] [enhab.automation.script.ui.TedeeTest] - Reply from Tedee Lock : {"error-code":2, "error-description":"BLE API error"}

You can limit the rule execution by adding some “But only if” conditions to the final rule by yourself, like execution is only allowed within 6.0 AM to 10.0 PM.

Language: JS scripting

Dependencies:

you have to install third party file - npm install crypto-js - in $/conf/automation/js/node-modules

Changelog

Version 0.1

  • initial release

Resources

uid:  kroenert:tedee
label:  Tedee Lock
description:  Opening and Closing the Tedee lock via Tedee bridge
configDescriptions:
  - description: Item for opening
    label: Item opening the lock
    name: openLockItem
    required: true
    type: TEXT
    context: item
    filterCriteria:
      - name: type
        value: Switch
  - description: Item for closing
    label: Item closing the lock
    name: closeLockItem
    required: true
    type: TEXT
    context: item
    filterCriteria:
      - name: type
        value: Switch
  - description: Ip adress of the Tedee bridge
    label: Bridge IP
    name: bridge_Ip
    required: true
    type: TEXT
    context: network-address
  - description: API Token - from Tedee App
    label: API Token
    name: bridgeApiToken
    required: true
    type: TEXT
  - description: Lock ID - from Tedee App
    label: Lock ID
    name: lock_Id
    required: true
    type: TEXT
  - description: Mode to open Lock
    label: Unlock Mode
    name: unlock_mode
    required: true
    type: TEXT
    options:
      - label: "no pullspring"
        value: "3"
      - label: "with pullspring"
        value: "4"
    limitToOptions: true
    defaultValue: 3
    type: TEXT
triggers:
  - id: "1"
    configuration:
      itemName: "{{closeLockItem}}"
      state: "ON"
    type: core.ItemStateChangeTrigger
  - id: "2"
    configuration:
      itemName: "{{openLockItem}}"
      state: "ON"
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "3"
    configuration:
      type: application/javascript
      script: >
        var CryptoJS = require('crypto-js');
        function getApiKey(ret_bridgeApiToken){
          var timestamp = new Date().getTime();
          var hash = CryptoJS.SHA256(ret_bridgeApiToken+timestamp).toString();
          var ret_api_key = hash+timestamp;
          return ret_api_key;
        }
        if ((items.{{closeLockItem}}.state == "ON") || (items.{{openLockItem}}.state == "ON")) {
          var api_key = getApiKey("{{bridgeApiToken}}");
          var content_type = "application/json";
          var content= "Content-Length: 0 ";
          if (items.{{closeLockItem}}.state == "ON") {
            var header = new Map();
                  header.set( "accept","*/*");
                  header.set( "api_token",api_key);
            var lock_url   = "http://"+"{{bridge_Ip}}"+"/v1.0/lock/"+"{{lock_Id}}"+"/lock";
          }
          if (items.{{openLockItem}}.state == "ON"){
            var header = new Map();
                  header.set( "accept","*/*");
                  header.set( "mode","{{unlock_mode}}");
                  header.set( "api_token",api_key);
            var lock_url   = "http://"+"{{bridge_Ip}}"+"/v1.0/lock/"+"{{lock_Id}}"+"/unlock";
          }
          var lockRequest   = actions.HTTP.sendHttpPostRequest(lock_url,content_type,content,header,  5000);
          if ( lockRequest != "") console.log("Reply from Tedee Lock : "+ lockRequest);
        }
        else{
          console.log("Event not excisting");
        }
    type: script.ScriptAction

To get the state of the lock, you can use the OH add-on “webhook”.

For initializing the Tedee bridge, you can use “Postman” -more information here

Tedee Bridge API

Against the Tedee documentation, you can leave the header empty while setting the webhook. This will trigger every event in Tedee Lock.

{
  "url": "http://192.168.1.69:8080/webhook/callback",
  "method": "POST",
  "headers": [ ]
}

That’s my configuration of the Webhook thing, which will give you sufficent room to evaluate any rules and items.

UID: webhook:Webhook:Tedee
label: Tedee Webhook
thingTypeUID: webhook:Webhook
configuration:
  expression: resp.status=200;
channels:
  - id: lastCall
    channelTypeUID: webhook:lastCall-channel
    label: Last request
    description: Timestamp of the last request to the webhook.
    configuration: {}
  - id: tedeeStatus
    channelTypeUID: webhook:string-channel
    label: Tedee Schloss Status
    configuration:
      expression: return req.body.json.data.state
  - id: tedeeGesamt
    channelTypeUID: webhook:string-channel
    label: Tedee gesamt
    description: all
    configuration:
      expression: return req.body.text
  - id: tedeeEvent
    channelTypeUID: webhook:string-channel
    label: Tedee Event
    configuration:
      expression: return req.body.json.event

that’s my rule to react to lock events

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: TedeeWebhookEvent
    type: core.ItemStateUpdateTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript
      script: >-
        var tedeeEvent = items.TedeeWebhookEvent.state;

        var tedeeString = items.TedeeLockString.state;


        switch (tedeeEvent){
          
            case "backend-connection-changed" :
              console.log('Tedee rule Aktion = '+ tedeeEvent);
        //      var wert =
        actions.Transformation.transform("JSONPATH","$.isConnected"
        ,bridgeRequest); 
              break;
            
            case "device-connection-changed" :
              console.log('Tedee rule Aktion = '+ tedeeEvent);
        //      var wert =
        actions.Transformation.transform("JSONPATH","$.isConnected"
        ,bridgeRequest);
            break;  
            
            case "device-settings-changed" :
              console.log('Tedee rule Aktion = '+ tedeeEvent);
        //      var wert =
        actions.Transformation.transform("JSONPATH","$.isConnected"
        ,bridgeRequest);
              break; 
            
            case "lock-status-changed" :
              console.log('Tedee rule Aktion = '+ tedeeEvent);    
        //      var wert =
        actions.Transformation.transform("JSONPATH","$.isConnected"
        ,bridgeRequest);
              break;
            
            case "device-battery-level-changed" :
                  console.log('Tedee rule Aktion = '+ tedeeEvent);  
              var wert = actions.Transformation.transform("JSONPATH","$.data.batteryLevel" ,tedeeString);
                  items.TedeeLockBatterie.postUpdate(wert);
              break;
            
            case "device-battery-start-charging" :
              console.log('Tedee rule Aktion = '+ tedeeEvent);  
        //      var wert =
        actions.Transformation.transform("JSONPATH","$.data.batteryLevel"
        ,tedeeString);

        //      items.TedeeLockBatterie.postUpdate(wert);
              break;    
            
            case "device-battery-stop-charging" :
              console.log('Tedee rule Aktion = '+ tedeeEvent);  
        //      var wert =
        actions.Transformation.transform("JSONPATH","$.isConnected"
        ,bridgeRequest);
              break;    
            
            case "device-battery-fully-charged" :
              console.log('Tedee rule Aktion = '+ tedeeEvent);
        //      var wert =
        actions.Transformation.transform("JSONPATH","$.isConnected"
        ,bridgeRequest);
              break;
            
            default :
              console.log('Tedee rule Aktion = kein Event gefunden');
        }
    type: script.ScriptAction