Advertisement
Guest User

ioBroker tahoma

a guest
Sep 26th, 2018
1,580
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var request = require('request');
  2.  
  3. // enable debugging mode
  4. //request.debug = true;
  5.  
  6. var lastEventTime = new Date().getTime();
  7.  
  8. var rawDeviceData = false;
  9. var tahomaJar = request.jar();
  10. var baseRequest = request.defaults({
  11.   headers: {
  12.         'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36'},
  13.   jar: tahomaJar
  14. });
  15.  
  16. var tahomaDevices = {};
  17. var Map_DeviceURL2StateName = {};
  18.  
  19. var userName = „Benutzer Name hier eintragen“;
  20. var passWord = „Kennwort hier eintragen“;
  21.  
  22. var baseURL = 'https://www.tahomalink.com/enduser-mobile-web/externalAPI/json/';
  23. var baseURLApply = 'https://www.tahomalink.com/enduser-mobile-web/enduserAPI/';
  24.  
  25. var isConnectedInternal = false;
  26.  
  27. createState('tahoma.connected', false, {
  28.   read: true,
  29.   write: true,
  30.   name: "connection status of tahoma",
  31.   type: "boolean",
  32.   def: false
  33. });
  34.  
  35. createOrUpdateState('tahoma.update', false, {
  36.     read: true,
  37.     write: true,
  38.     role: "button"
  39. });
  40. on('javascript.0.tahoma.update', function(obj)
  41. {
  42.     log("tahoma refresh states requested: " + obj);
  43.    
  44.     if (obj.newState.val)
  45.     {
  46.         getAllStates(function ()
  47.         {
  48.             setState("javascript.0.tahoma.update", false);
  49.         });  
  50.     }
  51. });
  52.  
  53. function isConnected()
  54. {
  55.     return isConnectedInternal;
  56. }
  57. function setConnected(connected)
  58. {
  59.     isConnectedInternal = connected;
  60.    
  61.     setState('javascript.0.tahoma.connected', connected, true);
  62. }
  63.  
  64. function getCreateStateOptions4Widget(widget)
  65. {
  66.     if (widget === 'PositionableRollerShutter')
  67.     {
  68.         return {
  69.                 "role":  "blind",
  70.         };
  71.     }
  72.    
  73.     if (widget === 'LuminanceSensor')
  74.     {
  75.         return {
  76.             "role":  "sensor"
  77.         };
  78.     }
  79.    
  80.     return {
  81.                 read: true,
  82.                 write: false,
  83.                 role: "state"
  84.             };
  85. }
  86.  
  87. function getCreateStateOptions4State(widget, stateName)
  88. {
  89.     if (stateName === "core:ClosureState")
  90.     {
  91.         return {
  92.                 "type":  "number",               // optional,  default "number"
  93.                 "read":  true,                   // mandatory, default true
  94.                 "write": true,                   // mandatory, default true
  95.                 "min":   0,                      // optional,  default 0
  96.                 "max":   100,                    // optional,  default 100
  97.                 "unit":  "%",                    // optional,  default %
  98.                 "role":  "level.blind"           // mandatory
  99.            };
  100.     }
  101.     if (stateName === "core:SlateOrientationState")
  102.     {
  103.         return {
  104.                 "type":  "number",               // optional,  default "number"
  105.                 "read":  true,                   // mandatory, default true
  106.                 "write": true,                   // mandatory, default true
  107.                 "min":   0,                      // optional,  default 0
  108.                 "max":   100,                    // optional,  default 100
  109.                 "unit":  "%",                    // optional,  default %
  110.                 "role":  "level.blind.orientation"           // mandatory
  111.            };
  112.     }
  113.     if (stateName === "core:LuminanceState")
  114.     {
  115.         return {
  116.                 "type":  "number",               // optional,  default "number"
  117.                 "read":  true,                   // mandatory, default true
  118.                 "write": false,                   // mandatory, default true
  119.                 "min":   0,                      // optional,  default 0
  120.                 "max":   100000,                    // optional,  default 100
  121.                 "unit":  "Lux",                    // optional,  default %
  122.                 "role":  "level.color.luminance"           // mandatory
  123.            };
  124.     }
  125.    
  126.     return {
  127.                 read: true,
  128.                 write: false,
  129.                 role: "state"
  130.             };
  131. }
  132.  
  133. function send(requestPath, payload, callback)
  134. {
  135.     login(function(err,data)
  136.     {
  137.         if (err)
  138.         {
  139.             return callback(err, data);
  140.         }
  141.        
  142.         sendInternal(requestPath, payload, callback);
  143.     });
  144. }
  145.  
  146. function sendInternal(requestPath, payload, callback)
  147. {
  148.     var url = baseURL + requestPath;
  149.    
  150.     if (requestPath.endsWith("apply"))
  151.     {
  152.         url = baseURLApply + requestPath + "/highPriority";
  153.     }
  154.     else if (requestPath === '/setup/devices/states/refresh')
  155.     {
  156.         url = baseURLApply + requestPath;
  157.     }
  158.    
  159.     var formPayload = null;
  160.     var jsonPayload = null;
  161.    
  162.     if (requestPath === 'login')
  163.     {
  164.         formPayload = payload;
  165.     }
  166.     else
  167.     {
  168.         jsonPayload = payload;
  169.     }
  170.    
  171.     log("perform " + requestPath + " with payload:" + JSON.stringify(payload), 'debug');
  172.  
  173.     baseRequest.post(
  174.         {
  175.             url:    url,
  176.             json:   jsonPayload,
  177.             form:   formPayload
  178.         },
  179.         cb(function(error, response, body)
  180.         {
  181.             if (!error && response.statusCode === 200)
  182.             {
  183.                 if (requestPath === 'login')
  184.                 {
  185.                     callback(false, JSON.parse(body));
  186.                 }
  187.                 else
  188.                 {
  189.                     callback(false, body);
  190.                 }
  191.             }
  192.             else if (response && requestPath !== 'logout'
  193.                 && (response.statusCode === 401 || response.statusCode === 403))
  194.             {
  195.                 //log("error during tahomalink request: " + response.statusText + " ->" + response.statusCode + " retry "  + requestPath, 'error');
  196.                
  197.                 // session expired?
  198.                 setConnected(false);
  199.                 send(requestPath, payload, callback);
  200.             }
  201.             else
  202.             {
  203.                 log("error during tahomalink request: " + error, 'error');
  204.                
  205.                 var result = {};        
  206.                 result.error = error;
  207.                
  208.                 if(typeof response !== "undefined")
  209.                 {
  210.                     log("response status: " + response.statusCode + " " + response.statusText,'debug');
  211.                    
  212.                     result.responseStatusCode = response.statusCode;
  213.                     result.responseStatusText = response.statusText;
  214.                 }
  215.                
  216.                 callback(true, result);
  217.             }
  218.     }));
  219. }
  220.  
  221. function logout(callback)
  222. {
  223.     var performLogout = isConnected();
  224.     setConnected(false);
  225.    
  226.     if (performLogout)
  227.     {
  228.         sendInternal("logout", {}, function (err, data)
  229.         {
  230.             callback(err, data);
  231.         });
  232.     }
  233.     else
  234.     {
  235.         callback(false, {});
  236.     }
  237. }
  238.  
  239. function login(callback)
  240. {
  241.     if (!isConnected())
  242.     {
  243.         var payload = {'userId': userName, 'userPassword': passWord};
  244.            
  245.         var result = sendInternal("login", payload, cb(function (err, data)
  246.         {
  247.             if (err || !data.success)
  248.             {
  249.                 return callback(true, data);
  250.             }
  251.            
  252.             lastEventTime = new Date().getTime();
  253.             setConnected(true);
  254.            
  255.             getUserInfo(function (err,data)
  256.             {
  257.                 if (!err)
  258.                 {
  259.                     return getSetup(callback);
  260.                 }
  261.                
  262.                 callback(err, data);
  263.             });
  264.            
  265.         }));
  266.          
  267.     }
  268.     else
  269.     {
  270.         callback(false, {});
  271.     }
  272.    
  273. }
  274.  
  275. function getUserInfo(callback)
  276. {
  277.     send('getEndUser', {},function (err, data)
  278.     {
  279.         if (!err)
  280.         {
  281.             updateData('userdata', data.endUser);
  282.            
  283.             callback(false, data);
  284.         }
  285.         else
  286.         {
  287.             log("getUserInfo failed!", 'error');
  288.         }
  289.        
  290.     });
  291. }
  292.  
  293. function updateGateWayData(gateways)
  294. {  
  295.     for (var i in gateways)
  296.     {
  297.         var gateway = gateways[i];
  298.        
  299.         updateData(gateway.gatewayId, gateway);
  300.     }
  301. }
  302.  
  303. function updateDevices(devices)
  304. {  
  305.     tahomaDevices = devices;
  306.    
  307.     for (var i in devices)
  308.     {
  309.         var device = devices[i];
  310.        
  311.         // just set the raw data from tahoma
  312.         updateDevice('devices.' + device.label, device);
  313.     }
  314. }
  315.  
  316. function updateDevice(name, deviceData)
  317. {  
  318.     createOrUpdateState('tahoma.' + name, '',
  319.         getCreateStateOptions4Widget(deviceData.widget));
  320.    
  321.     // device URL
  322.     createOrUpdateState('tahoma.' + name + '.deviceURL', deviceData.deviceURL);
  323.    
  324.     // states
  325.     for (var stateKey in deviceData.states)
  326.     {
  327.         var state = deviceData.states[stateKey];
  328.        
  329.         createOrUpdateState('tahoma.' + name + '.states.' + state.name,
  330.             mapValueTahoma2ioBroker(state.name, state.value),
  331.             getCreateStateOptions4State(deviceData.widget, state.name));
  332.     }
  333.    
  334.      // commands
  335.     for (var commandKey in deviceData.definition.commands)
  336.     {
  337.         var command = deviceData.definition.commands[commandKey];
  338.        
  339.         if (command.nparams === 0)
  340.         {
  341.             createOrUpdateState('tahoma.' + name + '.commands.' + command.commandName, false, {
  342.                 read: true,
  343.                 write: true,
  344.                 role: "button"
  345.             });
  346.         }
  347.     }
  348.            
  349.     // raw data
  350.     if (rawDeviceData)
  351.     {
  352.         for (var p in deviceData)
  353.         {
  354.             var value = deviceData[p];
  355.            
  356.             if (typeof(value) === 'object')
  357.             {
  358.                 updateData('raw.' + name + '.' + p, value);
  359.             }
  360.             else
  361.             {
  362.                 createOrUpdateState('tahoma.raw.' + name + '.' + p, value);
  363.             }
  364.         }
  365.     }
  366. }
  367.  
  368. function mapValueTahoma2ioBroker(stateName, stateValue)
  369. {
  370.     if (stateName === 'core:ClosureState')
  371.     {
  372.         // reverse order
  373.         //stateValue = 100 - stateValue;
  374.     }
  375.  
  376.     return stateValue;
  377. }      
  378.  
  379. function mapValueioBroker2Tahoma(stateName, stateValue)
  380. {
  381.     if (stateName === 'core:ClosureState')
  382.     {
  383.         // reverse order
  384.         //stateValue = 100 - stateValue;
  385.     }
  386.  
  387.     return stateValue;
  388. }      
  389.  
  390. function updateData(type, data)
  391. {  
  392.     for (var p in data)
  393.     {
  394.         var value = data[p];
  395.        
  396.         if (typeof(value) === 'object')
  397.         {
  398.             updateData(type + '.' + p, value);
  399.         }
  400.         else
  401.         {
  402.             createOrUpdateState('tahoma.' + type + '.' + p, value);
  403.         }
  404.     }
  405. }
  406.  
  407. function createOrUpdateState(key, value, options)
  408. {
  409.     key = key.replace(' ' , '_');
  410.     var state = getState("javascript.0." + key);
  411.    
  412.     if (value === "true" || value === "false")
  413.     {
  414.         value = value == "true";
  415.     }
  416.    
  417.     if (state.notExist)
  418.     {
  419.        
  420.         if (typeof(options) === 'undefined')
  421.         {
  422.             options = {
  423.                 read: true,
  424.                 write: false,
  425.                 type: "string"
  426.             };
  427.         }
  428.  
  429.         // create state
  430.         createState(key, value, 0, options);
  431.     }
  432.     else
  433.     {
  434.         setState("javascript.0." + key, value, true);
  435.     }
  436. }
  437.  
  438. function getSetup(callback)
  439. {
  440.     send('getSetup', {},function (err, data)
  441.     {
  442.         if (!err)
  443.         {
  444.             updateGateWayData(data.setup.gateways);
  445.             updateData('location', data.setup.location);
  446.             updateDevices(data.setup.devices);
  447.            
  448.             // delete old devices
  449.             deleteOldDevices();
  450.            
  451.             // update mapping table device URL to state key with label
  452.             $('javascript.0.tahoma.devices.*.deviceURL').each(function (id, i)
  453.             {
  454.                 var state = getState(id);
  455.                 Map_DeviceURL2StateName[state.val] = id.substr(0, id.indexOf(".deviceURL"));
  456.                
  457.                 //log("set mapping deviceURL to name: " + state.val + " -> " + id.substr(0, id.indexOf(".deviceURL")),'debug');
  458.             });
  459.            
  460.             // refresh
  461.             send('/setup/devices/states/refresh', {}, function (err,data)
  462.             {
  463.                 if (err)
  464.                 {
  465.                     log("refresh device state failed");
  466.                 }
  467.                 callback(err, {});  
  468.             });
  469.            
  470.         }
  471.         else
  472.         {
  473.             log("getSetup failed!",'error');
  474.            
  475.             callback(err, {});
  476.         }
  477.        
  478.     });
  479. }
  480.  
  481. function getAllStates()
  482. {
  483.     login(function (err, data)
  484.     {
  485.         if (err)
  486.         {
  487.             return;
  488.         }
  489.  
  490.         send("getEvents", {}, function (err,data)
  491.         {
  492.             if (err)
  493.             {
  494.                 return;
  495.             }
  496.            
  497.             updateDeviceStateFromEvent(data);
  498.         });
  499.     });
  500. }
  501.  
  502. function updateDeviceStateFromEvent(events)
  503. {
  504.     for (var i in events)
  505.     {
  506.         lastEventTime = new Date().getTime();
  507.         var event = events[i];
  508.    
  509.         if (event.name === 'DeviceStateChangedEvent')
  510.         {
  511.             updateDeviceState(event);
  512.         }
  513.     }
  514. }
  515.  
  516. function updateDeviceState(event)
  517. {
  518.     var deviceURL = event.deviceURL;
  519.     var states = event.deviceStates;
  520.    
  521.     var devicePath = Map_DeviceURL2StateName[deviceURL];
  522.     // tahoma.devices.XXX
  523.     // tahoma.devices.XXX.states.Y
  524.    
  525.     log("got event for device " + devicePath);
  526.  
  527.     for (var i in event.deviceStates)
  528.     {
  529.         var state = event.deviceStates[i];
  530.         var name = state.name;
  531.         var value = mapValueTahoma2ioBroker(name, state.value);
  532.        
  533.         log("found " + devicePath + '.states.' + name + " -> " + value);
  534.         setState(devicePath + '.states.' + name, value, true);
  535.     }
  536. }
  537.  
  538. function deleteOldDevices()
  539. {
  540.     var currentTime = new Date().getTime();
  541.    
  542.     $('javascript.0.tahoma.devices.*.lastUpdateTime').each(function (id, i)
  543.     {
  544.         var state = getState(id);
  545.         var device = id.substr(0, id.indexOf(".lastUpdateTime"));
  546.        
  547.         if (currentTime - state.ts > 5 * 60 * 1000)
  548.         {
  549.             // update older than 1 minute -> drop
  550.             log ("found old " + device + " -> " + new Date(state.ts),'debug');
  551.            
  552.             $(device + '.*').each(function (id, i)
  553.             {
  554.                 //log("delete state:" + id);
  555.                 deleteState(id);
  556.             });
  557.         }
  558.     });
  559. }
  560.  
  561. on(/^javascript\.0\.tahoma\.devices.*\.commands/,function(obj)
  562. {
  563.     if (obj.state.val)
  564.     {
  565.         var id = obj.id;
  566.       log("button pressed: " + id + " -> " + JSON.stringify(obj));
  567.      
  568.       var commandName = id.substr(id.lastIndexOf(".")+1);
  569.       var deviceURL = getState(id.substr(0, id.indexOf(".commands.")) + ".deviceURL").val;
  570.      
  571.       var payload = {'label':'command ' + commandName + ' from ioBroker',
  572.           'actions':[{
  573.             'deviceURL': deviceURL,
  574.             'commands': [{
  575.                 'name': commandName,
  576.                 'parameters': []
  577.             }]}]};
  578.    
  579.         send("exec/apply", payload, function(err, data)
  580.         {
  581.             // reset state
  582.             setState(obj.id, !obj.state.val);
  583.         });
  584.     }
  585. });
  586.  
  587. on(/^javascript\.0\.tahoma\.devices.*\.states.core:ClosureState/,function(obj)
  588. {
  589.     if (!obj.newState.ack)
  590.     {
  591.         var id = obj.id;
  592.           log("closure state changed: " + id + " -> " + JSON.stringify(obj));
  593.          
  594.           var commandName = "setClosure";
  595.           var deviceURL = getState(id.substr(0, id.indexOf(".states.")) + ".deviceURL").val;
  596.           var stateValue = obj.newState.val;
  597.           var roomName = id.substr(id.indexOf('.devices.')+9);
  598.          
  599.           roomName = roomName.substr(0,roomName.indexOf('.states'));
  600.          
  601.           var payload = {'label': roomName + ' - Positioniere auf ' + stateValue + ' % - ioBroker',
  602.               'actions':[{
  603.                 'deviceURL': deviceURL,
  604.                 'commands': [{
  605.                     'name': commandName,
  606.                     'parameters': [ mapValueioBroker2Tahoma('core:ClosureState', stateValue) ]
  607.                 }]}]};
  608.    
  609.             send("exec/apply", payload, function(err, data)
  610.             {
  611.                 // reset state
  612.                 //setState(obj.id, !obj.state.val);
  613.             });
  614.     }
  615. });
  616.  
  617. on(/^javascript\.0\.tahoma\.devices.*\.states.core:SlateOrientationState/,function(obj)
  618. {
  619.     if (!obj.newState.ack)
  620.     {
  621.         var id = obj.id;
  622.      
  623.       var commandName = "setOrientation";
  624.       var deviceURL = getState(id.substr(0, id.indexOf(".states.")) + ".deviceURL").val;
  625.       var stateValue = obj.newState.val;
  626.       var roomName = id.substr(id.indexOf('.devices.')+9);
  627.          
  628.         roomName = roomName.substr(0,roomName.indexOf('.states'));
  629.      
  630.       log("slate orientation changed: " + roomName + " -> " + stateValue);
  631.      
  632.      
  633.       var payload = {'label':roomName + ' - Ausrichtung ' + stateValue + ' % - ioBroker',
  634.           'actions':[{
  635.             'deviceURL': deviceURL,
  636.             'commands': [{
  637.                 'name': commandName,
  638.                 'parameters': [ mapValueioBroker2Tahoma('core:SlateOrientationState', stateValue) ]
  639.             }]}]};
  640.    
  641.         send("exec/apply", payload, function(err, data)
  642.         {
  643.             // reset state
  644.             //setState(obj.id, !obj.state.val);
  645.         });
  646.        
  647.     }
  648. });
  649.  
  650. // if connected, update state all 5 seconds
  651. schedule("*/5 * * * * *", function ()
  652. {
  653.     // if connected, update states
  654.     if (isConnected())
  655.     {
  656.         getAllStates();
  657.        
  658.         if (new Date().getTime() - lastEventTime > 60 * 1000)
  659.         {
  660.             // no events within last 60 seconds
  661.             logout(function () {});
  662.         }
  663.     }
  664. });
  665.  
  666. // update state all 5 minutes
  667. schedule("*/5 * * * *", function ()
  668. {
  669.     log("update tahoma all 5 minutes");
  670.     getAllStates();
  671. });
  672.  
  673. onStop(function (callback) {
  674.     logout(function (err, data)
  675.         {
  676.             callback();
  677.         });
  678. }, 10000 /*ms*/);
  679.  
  680. // start script
  681. getAllStates();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement