Advertisement
Guest User

Untitled

a guest
Sep 29th, 2018
420
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 = "";
  20. var passWord = "";
  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" || stateName === "core:TargetClosureState")
  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' || stateName === 'core:TargetClosureState')
  371.     {
  372.         stateValue = parseInt(stateValue,10);
  373.     }
  374.  
  375.     return stateValue;
  376. }      
  377.  
  378. function mapValueioBroker2Tahoma(stateName, stateValue)
  379. {
  380.     if (stateName === 'core:ClosureState' || stateName === 'core:TargetClosureState')
  381.     {
  382.         stateValue = parseInt(stateValue,10);
  383.     }
  384.  
  385.     return stateValue;
  386. }      
  387.  
  388. function updateData(type, data)
  389. {  
  390.     for (var p in data)
  391.     {
  392.         var value = data[p];
  393.        
  394.         if (typeof(value) === 'object')
  395.         {
  396.             updateData(type + '.' + p, value);
  397.         }
  398.         else
  399.         {
  400.             createOrUpdateState('tahoma.' + type + '.' + p, value);
  401.         }
  402.     }
  403. }
  404.  
  405. function createOrUpdateState(key, value, options)
  406. {
  407.     key = key.replace(' ' , '_');
  408.     var state = getState("javascript.0." + key);
  409.    
  410.     if (value === "true" || value === "false")
  411.     {
  412.         value = value == "true";
  413.     }
  414.    
  415.     if (state.notExist)
  416.     {
  417.        
  418.         if (typeof(options) === 'undefined')
  419.         {
  420.             options = {
  421.                 read: true,
  422.                 write: false,
  423.                 type: "string"
  424.             };
  425.         }
  426.  
  427.         // create state
  428.         createState(key, value, 0, options);
  429.     }
  430.     else
  431.     {
  432.         setState("javascript.0." + key, value, true);
  433.     }
  434. }
  435.  
  436. function getSetup(callback)
  437. {
  438.     send('getSetup', {},function (err, data)
  439.     {
  440.         if (!err)
  441.         {
  442.             updateGateWayData(data.setup.gateways);
  443.             updateData('location', data.setup.location);
  444.             updateDevices(data.setup.devices);
  445.            
  446.             // delete old devices
  447.             deleteOldDevices();
  448.            
  449.             // update mapping table device URL to state key with label
  450.             $('javascript.0.tahoma.devices.*.deviceURL').each(function (id, i)
  451.             {
  452.                 var state = getState(id);
  453.                 Map_DeviceURL2StateName[state.val] = id.substr(0, id.indexOf(".deviceURL"));
  454.                
  455.                 //log("set mapping deviceURL to name: " + state.val + " -> " + id.substr(0, id.indexOf(".deviceURL")),'debug');
  456.             });
  457.            
  458.             // refresh
  459.             send('/setup/devices/states/refresh', {}, function (err,data)
  460.             {
  461.                 if (err)
  462.                 {
  463.                     log("refresh device state failed");
  464.                 }
  465.                 callback(err, {});  
  466.             });
  467.            
  468.         }
  469.         else
  470.         {
  471.             log("getSetup failed!",'error');
  472.            
  473.             callback(err, {});
  474.         }
  475.        
  476.     });
  477. }
  478.  
  479. function getAllStates()
  480. {
  481.     login(function (err, data)
  482.     {
  483.         if (err)
  484.         {
  485.             return;
  486.         }
  487.  
  488.         send("getEvents", {}, function (err,data)
  489.         {
  490.             if (err)
  491.             {
  492.                 return;
  493.             }
  494.            
  495.             updateDeviceStateFromEvent(data);
  496.         });
  497.     });
  498. }
  499.  
  500. function updateDeviceStateFromEvent(events)
  501. {
  502.     for (var i in events)
  503.     {
  504.         lastEventTime = new Date().getTime();
  505.         var event = events[i];
  506.    
  507.         if (event.name === 'DeviceStateChangedEvent')
  508.         {
  509.             updateDeviceState(event);
  510.         }
  511.     }
  512. }
  513.  
  514. function updateDeviceState(event)
  515. {
  516.     var deviceURL = event.deviceURL;
  517.     var states = event.deviceStates;
  518.    
  519.     var devicePath = Map_DeviceURL2StateName[deviceURL];
  520.     // tahoma.devices.XXX
  521.     // tahoma.devices.XXX.states.Y
  522.    
  523.     log("got event for device " + devicePath);
  524.  
  525.     for (var i in event.deviceStates)
  526.     {
  527.         var state = event.deviceStates[i];
  528.         var name = state.name;
  529.         var value = mapValueTahoma2ioBroker(name, state.value);
  530.        
  531.         log("found " + devicePath + '.states.' + name + " -> " + value);
  532.         setState(devicePath + '.states.' + name, value, true);
  533.     }
  534. }
  535.  
  536. function deleteOldDevices()
  537. {
  538.     var currentTime = new Date().getTime();
  539.    
  540.     $('javascript.0.tahoma.devices.*.lastUpdateTime').each(function (id, i)
  541.     {
  542.         var state = getState(id);
  543.         var device = id.substr(0, id.indexOf(".lastUpdateTime"));
  544.        
  545.         if (currentTime - state.ts > 5 * 60 * 1000)
  546.         {
  547.             // update older than 1 minute -> drop
  548.             log ("found old " + device + " -> " + new Date(state.ts),'debug');
  549.            
  550.             $(device + '.*').each(function (id, i)
  551.             {
  552.                 //log("delete state:" + id);
  553.                 deleteState(id);
  554.             });
  555.         }
  556.     });
  557. }
  558.  
  559. on(/^javascript\.0\.tahoma\.devices.*\.commands/,function(obj)
  560. {
  561.     if (obj.state.val)
  562.     {
  563.         var id = obj.id;
  564.       log("button pressed: " + id + " -> " + JSON.stringify(obj));
  565.      
  566.       var commandName = id.substr(id.lastIndexOf(".")+1);
  567.       var deviceURL = getState(id.substr(0, id.indexOf(".commands.")) + ".deviceURL").val;
  568.      
  569.       var payload = {'label':'command ' + commandName + ' from ioBroker',
  570.           'actions':[{
  571.             'deviceURL': deviceURL,
  572.             'commands': [{
  573.                 'name': commandName,
  574.                 'parameters': []
  575.             }]}]};
  576.    
  577.         send("exec/apply", payload, function(err, data)
  578.         {
  579.             // reset state
  580.             setState(obj.id, !obj.state.val);
  581.         });
  582.     }
  583. });
  584.  
  585. on(/^javascript\.0\.tahoma\.devices.*\.states.core:*\ClosureState/,function(obj)
  586. {
  587.     if (!obj.newState.ack)
  588.     {
  589.         var id = obj.id;
  590.           log("closure state changed: " + id + " -> " + JSON.stringify(obj));
  591.          
  592.           var commandName = "setClosure";
  593.           var deviceURL = getState(id.substr(0, id.indexOf(".states.")) + ".deviceURL").val;
  594.           var stateValue = obj.newState.val;
  595.           var roomName = id.substr(id.indexOf('.devices.')+9);
  596.          
  597.           roomName = roomName.substr(0,roomName.indexOf('.states'));
  598.          
  599.           var payload = {'label': roomName + ' - Positioniere auf ' + stateValue + ' % - ioBroker',
  600.               'actions':[{
  601.                 'deviceURL': deviceURL,
  602.                 'commands': [{
  603.                     'name': commandName,
  604.                     'parameters': [ mapValueioBroker2Tahoma('core:ClosureState', stateValue) ]
  605.                 }]}]};
  606.    
  607.             send("exec/apply", payload, function(err, data)
  608.             {
  609.                 // reset state
  610.                 //setState(obj.id, !obj.state.val);
  611.             });
  612.     }
  613. });
  614.  
  615. on(/^javascript\.0\.tahoma\.devices.*\.states.core:SlateOrientationState/,function(obj)
  616. {
  617.     if (!obj.newState.ack)
  618.     {
  619.         var id = obj.id;
  620.      
  621.       var commandName = "setOrientation";
  622.       var deviceURL = getState(id.substr(0, id.indexOf(".states.")) + ".deviceURL").val;
  623.       var stateValue = obj.newState.val;
  624.       var roomName = id.substr(id.indexOf('.devices.')+9);
  625.          
  626.         roomName = roomName.substr(0,roomName.indexOf('.states'));
  627.      
  628.       log("slate orientation changed: " + roomName + " -> " + stateValue);
  629.      
  630.      
  631.       var payload = {'label':roomName + ' - Ausrichtung ' + stateValue + ' % - ioBroker',
  632.           'actions':[{
  633.             'deviceURL': deviceURL,
  634.             'commands': [{
  635.                 'name': commandName,
  636.                 'parameters': [ mapValueioBroker2Tahoma('core:SlateOrientationState', stateValue) ]
  637.             }]}]};
  638.    
  639.         send("exec/apply", payload, function(err, data)
  640.         {
  641.             // reset state
  642.             //setState(obj.id, !obj.state.val);
  643.         });
  644.        
  645.     }
  646. });
  647.  
  648. // if connected, update state all 5 seconds
  649. schedule("*/5 * * * * *", function ()
  650. {
  651.     // if connected, update states
  652.     if (isConnected())
  653.     {
  654.         getAllStates();
  655.        
  656.         if (new Date().getTime() - lastEventTime > 60 * 1000)
  657.         {
  658.             // no events within last 60 seconds
  659.             logout(function () {});
  660.         }
  661.     }
  662. });
  663.  
  664. // update state all 5 minutes
  665. schedule("*/5 * * * *", function ()
  666. {
  667.     log("update tahoma all 5 minutes");
  668.     getAllStates();
  669. });
  670.  
  671. onStop(function (callback) {
  672.     logout(function (err, data)
  673.         {
  674.             callback();
  675.         });
  676. }, 10000 /*ms*/);
  677.  
  678. // start script
  679. getAllStates();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement