Changes in / [1:3]


Ignore:
Location:
/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • /trunk/L_VeraConnectWWN1.lua

    r1 r3  
    11module("L_VeraConnectWWN1", package.seeall) 
    2  
    3 require("socket") 
    4 local ssl = require("ssl") 
    5 local peer = socket.tcp() 
    6 local params = { 
    7     mode = "client", 
    8     protocol = "tlsv1", 
    9     verify = {"none"}, 
    10     options = {"no_compression"}, 
    11     ciphers = "ALL", 
    12 } 
    13  
     2-- andrei : {"access_token":"c.CzL215BijVuzFgznRCW9QKvA0eblyxSMI9ad7klSX87vkpDyI0XxiftueUPWqDim9ejCCrYJ9r0WCHhJz16clWAxoLTqhcbXeYT45kzbeJ8gC5UwLIxdrc0v2teyuVhnSz6ZLmTJ2TEqEXIm","expires_in":315360000} 
     3-- florin : {"access_token":"c.7zKZ8yzOgDWUKGUTeBKz1JOPRAM6uWOse7Eb6jnfcKTT23hyOLKV5pv3vafKRp6wHlRHkVjknRABDa4NKnxAJNl6lq4GIoJPXIX4mby3ubcMprxqrM2GFN0EGb2WdWQwtsTblXLVgkKvGG2Y","expires_in":315360000} 
     4 
     5--require("socket") 
     6local ltn12 = require("ltn12") 
     7local dkjson = require ("dkjson") 
     8local https = require("ssl.https") 
     9local http = require ("socket.http") 
     10--local mime = require("mime") 
    1411-- Flags 
    1512local DEBUG_MODE = false 
    1613local FLAGS = { 
    17     PARTITIONS = false, 
    18     ZONES = true 
     14     
    1915} 
    2016 
     
    2319    TEMPERATURE_SENSOR  = "D_TemperatureSensor1.xml", 
    2420    THERMOSTAT          = "D_HVAC_ZoneThermostat1.xml", 
    25     SMOKE_SENSOR        = "D_SmokeSensor1.xml" 
     21    HUMIDITY            = "D_HumiditySensor1.xml", 
     22    SMOKE_SENSOR        = "D_SmokeSensor1.xml", 
     23    BINARY_LIGHT        = "D_BinaryLight1.xml" 
    2624} 
    2725 
     
    2927    TEMPERATURE_SENSOR  = "urn:schemas-micasaverde-com:device:TemperatureSensor:1", 
    3028    THERMOSTAT          = "urn:schemas-upnp-org:device:HVAC_ZoneThermostat:1", 
    31     SMOKE_SENSOR        = "urn:schemas-micasaverde-com:device:SmokeSensor:1" 
     29    HUMIDITY            = "urn:schemas-micasaverde-com:device:HumiditySensor:1", 
     30    SMOKE_SENSOR        = "urn:schemas-micasaverde-com:device:SmokeSensor:1", 
     31    BINARY_LIGHT        = "urn:schemas-upnp-org:device:BinaryLight:1" 
    3232} 
    3333 
     
    5555-- LastUpdate 
    5656local DISPLAY_SECONDS = 20 
    57 local POLLING_RATE = 10 -- 5 -- 30 --"PollFrequency" 
     57local POLLING_RATE = 5 -- 30 --"PollFrequency" 
    5858 
    5959-- Globals 
     
    6161local lug_device = nil 
    6262local g_appendPtr -- The pointer passed to luup.chdev.append 
    63 local g_pinCodes = {} 
    6463local g_taskHandle = -1 
    65 local g_errorMessage = nil 
    6664local g_lastTask = os.time() -- The time when the status message was last updated. 
    67 local g_users = nil 
    68 local g_areas = { 
     65local g_username = "" 
     66local g_password = "" 
     67local g_fileSize = 0 
     68local g_maxFileSize = 5 * 1024 * 1024 
     69local g_thermostats = { 
    6970    -- .panelID = "" 
    7071    -- .name = "" 
    7172    -- .devId 
    7273} 
     74local g_smoke = { 
     75 
     76} 
     77local g_structures = { 
     78 
     79} 
    7380 
    7481local ipAddress 
    7582local ipPort 
    76  
     83local NEST_UA = "Nest/1.1.0.10 CFNetwork/548.0.4" 
     84local nest_token = "" 
     85local nest_ClientID = "5b1585a5-b64e-4759-903e-895ac9373245" 
     86local nest_Secret = "noR9PTaBOHx6kONdieaClyyBX" 
     87local g_URL = "https://developer-api.nest.com" 
     88local temperatureScale = "" 
     89-- 7W69Q34L 
    7790--------------------------------------------------------- 
    7891-----------------Generic Utils--------------------------- 
     
    100113    g_lastTask = os.time() 
    101114    luup.call_delay("clearTask", DISPLAY_SECONDS) 
    102 end 
    103  
    104  
    105 local function wait(peer, err) 
    106    if err == "timeout" or err == "wantread" then 
    107         --log("***WANTREAD***") 
    108         socket.select({peer}, nil,0) 
    109     elseif err == "wantwrite" then 
    110         --log("***WANTWRITE***") 
    111         socket.select(nil, {peer},0) 
    112     else 
    113         --peer:close() 
    114         --os.exit(1) 
    115     end 
    116 end 
    117  
    118 local function send(str, peer) 
    119     local match = {"0","1","2","3","4","5","6","7","8","9"} 
    120     local length  = tostring(str:len()) 
    121     local tosend = fromhex("01") 
    122  
    123     for _,v in pairs(match) do 
    124         if v == length then 
    125             length = string.format('%02s',length) 
    126         end 
    127     end 
    128  
    129     tosend = tosend .. fromhex(length) .. str 
    130     debug("(Bosch Plugin)::(send) : Sending...") 
    131     peer:settimeout(0.3) 
    132     local succ, err = peer:send(tosend) 
    133     debug("(Bosch Plugin)::(send) : Waiting...") 
    134     wait(peer, err) 
    135     if succ then 
    136         debug("(Bosch Plugin)::(send) : Succesifully sent : [".. tohex(tosend) .. "] with length = [" .. succ .. "]") 
    137     else 
    138         debug("(Bosch Plugin)::(send) : Sending error!!! .. Reconnecting ... ") 
    139         reconnect() 
    140         if err then 
    141             debug("(Bosch Plugin)::(send) : ERROR : " .. err) 
    142         end 
    143     end 
    144 end 
    145  
    146 local function receive() 
    147     local data = nil 
    148     local status 
    149     local partials = nil 
    150     local length = 0 
    151     local start = os.time() 
    152     local stop 
    153     while (not partials) or (tostring(partials)  == "")  do 
    154         data , status, partials = peer:receive() 
    155         stop = os.time() 
    156         if (stop - start) > 10 then 
    157             debug("partial = [" .. tostring(partial) .. "]") 
    158             debug("status = [" .. tostring(status) .. "]") 
    159             debug("data = [" .. tostring(data) .. "]") 
    160             return 
    161         end 
    162     end 
    163  
    164     return partials 
    165 end 
    166  
    167 local function login() 
    168     -- debug("in login()") 
    169  
    170     local data = readSettings() 
    171  
    172     -- if there is no username or password, then no matter what, don't proceed 
    173     if (data.username == "" or data.password == "") then 
    174         task("Please specify username and password.") 
    175         clearSession() 
    176         return 
    177     end 
    178  
    179     -- if there is old session data, it might still be good, so try it! 
    180     if (data.transport_url ~= "" and data.userid ~= "" and data.access_token ~= "") then 
    181         debug("assuming saved login credentials are still valid.") 
    182         return data 
    183     end 
    184  
    185     -- perform https POST to nest.com to login 
    186     local res = {} 
    187     local body = urlcode.encodetable{username = data.username, password = data.password} 
    188     local headers = {["user-agent"] = NEST_UA, 
    189                    ["content-length"] = string.len(body), 
    190                    ["content-type"] = "application/x-www-form-urlencoded"} 
    191     local url = { url = "https://home.nest.com/user/login", 
    192                 protocol = "tlsv1", 
    193                 method = "POST", 
    194                 source = ltn12.source.string(body), 
    195                 sink = ltn12.sink.table(res), 
    196                 headers = headers } 
    197  
    198     local one, code, headers, status = https.request(url) 
    199  
    200     if (code == 200) then 
    201         res = json.decode(table.concat(res)) 
    202  
    203         data.transport_url = res.urls.transport_url 
    204         data.userid = res.userid 
    205         data.access_token = res.access_token 
    206  
    207         task("Successful nest.com login.", TASK_SUCCESS) 
    208         saveSession(data.transport_url, data.userid, data.access_token) 
    209         return data 
    210     else 
    211         task("Failed to login: code=" .. tostring(code) .. ", status=" .. tostring(status)) 
    212         clearSession() 
    213     end 
    214 end 
    215  
    216 local function getPackageVersion() 
    217     debug("getPackageVersion", "Verifying packages...") 
    218     local REQUIRED_VERSION = { '1', '0', '1', 'e', '1' } 
    219     local stdout = io.popen("opkg list-installed | awk '/openssl-util/ {print $3}'") 
    220     local version = stdout:read("*a") 
    221     version = version:match("([^%s]+)") 
    222     stdout:close() 
    223     local i = 1 
    224     for c in version:gmatch("[^.-]") do 
    225             if c < REQUIRED_VERSION[i] then 
    226                 os.execute ("opkg install 'http://downloads.openwrt.org/attitude_adjustment/12.09/ramips/rt3883/packages/openssl-util_1.0.1e-1_ramips.ipk'") 
    227                 debug("(Bosch Plugin)::(getPackageVersion) : Updating openssl-util!!!") 
    228             end 
    229             i = i + 1 
    230     end 
    231     REQUIRED_VERSION = { '0', '5', '5'} 
    232     stdout = io.popen("opkg list-installed | awk '/luasec/ {print $3}'") 
    233     version = stdout:read("*a") 
    234     version = version:match("([^%s]+)") 
    235     stdout:close() 
    236     i = 1 
    237     for c in version:gmatch("[^.-]") do 
    238             if c < REQUIRED_VERSION[i] then 
    239                 os.execute ("opkg update") 
    240                 os.execute ("opkg install luasec") 
    241                 debug("(Bosch Plugin)::(getPackageVersion) : Updating luasec!!!") 
    242             end 
    243             i = i + 1 
    244     end 
    245     REQUIRED_VERSION = { '1', '0', '1', 'g', '1' } 
    246     stdout = io.popen("opkg list-installed | awk '/libopenssl/ {print $3}'") 
    247     version = stdout:read("*a") 
    248     version = version:match("([^%s]+)") 
    249     stdout:close() 
    250     i = 1 
    251     for c in version:gmatch("[^.-]") do 
    252             if c < REQUIRED_VERSION[i] then 
    253                 os.execute ("opkg install 'http://downloads.openwrt.org/attitude_adjustment/12.09/ramips/rt3883/packages/libopenssl_1.0.1g-1_ramips.ipk'") 
    254                 debug("(Bosch Plugin)::(getPackageVersion) : Updating libopenssl!!!") 
    255             end 
    256             i = i + 1 
    257     end 
    258     debug("(Bosch Plugin)::(getPackageVersion) : Packages OK") 
    259115end 
    260116 
     
    266122    return s 
    267123end 
     124 
     125local function getTemperatureScale() 
     126    local code, data = luup.inet.wget("http://localhost:3480/data_request?id=lu_sdata") 
     127    if (code == 0) then 
     128        data = dkjson.decode(data) 
     129    end 
     130    temperatureScale = ((code == 0) and (data ~= nil) and (data.temperature ~= nil)) and string.lower(data.temperature) or "f" 
     131end 
     132 
     133local function getNestDeviceID(device, data_structure) 
     134    for k,v in pairs (data_structure) do 
     135        if v.vera_id == device then 
     136            return v.device_id 
     137        end 
     138    end 
     139    return 
     140end 
     141 
     142local function nestRequest(method, headers, URL, data) 
     143    --debug("nestRequest","method = " .. method) 
     144    --debug("nestRequest","headers = " .. tostring(headers)) 
     145    --debug("nestRequest","URL = " .. URL) 
     146    --debug("nestRequest","URL = " .. URL) 
     147    local curlCommand = "" 
     148    if method == "GET" or method == "POST" then 
     149        curlCommand = "curl -k -L -X " .. method .. " " .. headers .. " " .. URL 
     150    elseif method == "STREAM" then 
     151        curlCommand = "curl -N -k -v -L " .. URL .. " " .. headers .. " > /tmp/NestOutput.txt &"  
     152    else 
     153        curlCommand = "curl -k -v -L -X " .. method .. " " .. URL .. " " .. headers .. " " .. data 
     154    end 
     155    --debug("nestRequest", "curlCommand = " .. tostring(curlCommand)) 
     156    local stdout = io.popen(curlCommand) 
     157    local response = stdout:read("*a") 
     158    stdout:close()   
     159        --debug("nestRequest", "curlCommand Response = [" .. tostring(response) .. "]") 
     160     
     161    if method == "STREAM" then 
     162        local fileCreated = io.open("/tmp/NestOutput.txt") 
     163        if fileCreated then 
     164            return true 
     165        else 
     166            return 
     167        end 
     168    end 
     169     
     170    if response and response ~= "" then 
     171        local json_string = response 
     172        local json_response = dkjson.decode(response) 
     173        local data = {} 
     174        if json_response.error then 
     175            debug("nestRequest", "error = " .. tostring(json_response.error)) 
     176            debug("nestRequest", "description = " .. tostring(json_response.error_description)) 
     177            return 
     178        else 
     179            return json_response, json_string 
     180        end 
     181        --[[ 
     182        for k,v in pairs(response) do 
     183            log("get_token","key = [" .. tostring(k) .. "] and value = [" .. v .. "]") 
     184        end 
     185        -- ]] 
     186        return response 
     187    else 
     188        debug("nestRequest", "Empty response!") 
     189        return 
     190    end 
     191end 
     192 
     193local function get_token() 
     194end 
     195 
     196local function clearNestOutputFile() 
     197    local stdout = io.popen("ps | grep 'curl -N -k -v -L https://developer-api.nest.com/devices.json?auth=' | grep -v 'grep'") 
     198    local response = stdout:read("*a") 
     199    stdout:close() 
     200    response = response:gmatch("(%d+) root") 
     201    for v in response do 
     202        debug("clearNestOutputFile", "Killed process " .. v) 
     203        os.execute("kill " .. v) 
     204    end 
     205    os.execute("rm /tmp/NestOutput.txt") 
     206end 
     207 
     208local function startStreaming() 
     209    clearNestOutputFile() 
     210    local url = g_URL .. "/devices.json?auth=" .. nest_token 
     211    local header = "-H \"Accept: text/event-stream\" " 
     212    local response, response_string = nestRequest("STREAM", header, url, "") 
     213    if response then 
     214        debug("startStreaming", "Streaming started successful!") 
     215    else 
     216        --debug("startStreaming", "Nest Data = " .. response_string) 
     217        debug("startStreaming", "ERROR : Could not start Stream!") 
     218    end 
     219end 
     220 
     221function getStreamEvents() 
     222    debug("getStreamEvents", "Getting Stream Events ...") 
     223    local lfs = require "lfs" 
     224    local fileSize = lfs.attributes("/tmp/NestOutput.txt", "size") 
     225    debug("getStreamEvents", "File size is = [" .. tostring(fileSize) .. "]") 
     226         
     227    -- check for new stram events 
     228    if fileSize then 
     229        if fileSize > g_fileSize then 
     230            local file = io.open("/tmp/NestOutput.txt") 
     231            file:seek("set", g_fileSize) 
     232            local newEvent = file:read("*a") 
     233            file:close() 
     234            newEvent = newEvent:match("data: (.*)}") 
     235            debug("getStreamEvents", "newEvent = [" .. tostring(newEvent) .. "]") 
     236            g_fileSize = fileSize 
     237            if newEvent and newEvent ~= "null" then 
     238                local response = dkjson.decode(newEvent .. "}") 
     239                local therm = response.data.thermostats 
     240                --[[ 
     241                for key,val in pairs(therm) do 
     242                    for k,v in pairs(val) do 
     243                        debug("getStreamEvents","therm[" .. key .."][" .. tostring(k) .. "]=[" .. tostring(v) .. "]") 
     244                    end 
     245                end  
     246                ]] 
     247                if therm then 
     248                    for i=1,#g_thermostats do 
     249                        if g_thermostats[i].device_id == therm[g_thermostats[i].device_id].device_id then 
     250                            for k,v in pairs(therm[g_thermostats[i].device_id]) do 
     251                                if v ~= g_thermostats[i][k] then 
     252                                    g_thermostats[i][k] = v 
     253                                    flagThermostat = true 
     254                                    debug("getStreamEvents", "updating g_thermostats[" .. i .. "][" .. k .. "] with value =" .. tostring(v)) 
     255                                end 
     256                            end 
     257                        end 
     258                    end 
     259                end 
     260                debug("getStreamEvents", "Verifying Smoke and CO detector/s!") 
     261                local smokePoll = response.data.smoke_co_alarms 
     262                --[[ 
     263                for key, val in pairs(smokePoll) do 
     264                    for k,v in pairs(val) do 
     265                        debug("getStreamEvents","smokePoll[" .. key .."][" .. tostring(k) .. "]=[" .. tostring(v) .. "]") 
     266                    end 
     267                end  
     268                ]] 
     269                if smokePoll then 
     270                    for i=1,#g_smoke do 
     271                        if g_smoke[i].device_id == smokePoll[g_smoke[i].device_id].device_id then 
     272                            for k,v in pairs(smokePoll[g_smoke[i].device_id]) do 
     273                                if v ~= g_smoke[i][k] then 
     274                                    g_smoke[i][k] = v 
     275                                    flagSmoke = true 
     276                                    debug("getStreamEvents", "updating g_smoke[" .. i .. "][" .. k .. "] with value =" .. tostring(v)) 
     277                                end 
     278                            end 
     279                        end 
     280                    end 
     281                end 
     282            end -- if newEvent 
     283            if flagThermostat then 
     284                updateThermostatValues() 
     285            end 
     286            if flagSmoke then 
     287                --updateSmokeValues() 
     288            end 
     289        end -- if fileSize > g_fileSize 
     290    end 
     291    -- check file size and delete if needed 
     292    if tonumber(fileSize) > g_maxFileSize then 
     293        -- delete /tmp/NestOutput.txt file & restart streaming 
     294        startStreaming() 
     295        debug("getStreamEvents", "Restarting Streaming!") 
     296    end 
     297    luup.call_delay("getStreamEvents", POLLING_RATE) 
     298end 
     299 
     300local function getNestData() 
     301    local url = g_URL .. "?auth=" .. nest_token 
     302    local header = "-H 'Accept: application/json'" 
     303    local response, response_string = nestRequest("GET", header, url, "") 
     304    if not response then 
     305        debug("getNestData", "ERROR : Could not get Nest Data!") 
     306    else 
     307        debug("getNestData", "Nest Data = " .. response_string) 
     308        if response.devices.thermostats then 
     309            local count = 1 
     310            g_thermostats[count] = {} 
     311            for k,v in pairs(response.devices.thermostats) do 
     312                g_thermostats[count].device_id = v.device_id 
     313                g_thermostats[count].name = v.name 
     314                g_thermostats[count].name_long = v.name_long 
     315                g_thermostats[count].locale = v.locale 
     316                g_thermostats[count].structure_id = v.structure_id 
     317                g_thermostats[count].software_version = v.software_version 
     318                g_thermostats[count].is_online = v.is_online 
     319                g_thermostats[count].last_connection = v.last_connection 
     320                g_thermostats[count].can_cool = v.can_cool 
     321                g_thermostats[count].can_heat = v.can_heat 
     322                g_thermostats[count].is_using_emergency_heat = v.is_using_emergency_heat 
     323                g_thermostats[count].has_fan = v.has_fan 
     324                g_thermostats[count].fan_timer_active = v.fan_timer_active 
     325                g_thermostats[count].fan_timer_timeout = v.fan_timer_timeout 
     326                g_thermostats[count].has_leaf = v.has_leaf 
     327                g_thermostats[count].temperature_scale = v.temperature_scale 
     328                g_thermostats[count].target_temperature_f = v.target_temperature_f 
     329                g_thermostats[count].target_temperature_c = v.target_temperature_c 
     330                g_thermostats[count].target_temperature_high_f = v.target_temperature_high_f 
     331                g_thermostats[count].target_temperature_high_c = v.target_temperature_high_c 
     332                g_thermostats[count].target_temperature_low_f = v.target_temperature_low_f 
     333                g_thermostats[count].target_temperature_low_c = v.target_temperature_low_c 
     334                g_thermostats[count].away_temperature_high_f = v.away_temperature_high_f 
     335                g_thermostats[count].away_temperature_high_c = v.away_temperature_high_c 
     336                g_thermostats[count].away_temperature_low_f = v.away_temperature_low_f 
     337                g_thermostats[count].away_temperature_low_c = v.away_temperature_low_c 
     338                g_thermostats[count].hvac_mode = v.hvac_mode 
     339                g_thermostats[count].ambient_temperature_f = v.ambient_temperature_f 
     340                g_thermostats[count].ambient_temperature_c = v.ambient_temperature_c 
     341                g_thermostats[count].humidity = v.humidity 
     342                count = count + 1 
     343            end 
     344        end 
     345        if response.devices.smoke_co_alarms then 
     346            local count = 1 
     347            g_smoke[count] = {} 
     348            for k,v in pairs(response.devices.smoke_co_alarms) do 
     349                g_smoke[count].name = v.name 
     350                g_smoke[count].name_long = v.name_long 
     351                g_smoke[count].locale = v.locale 
     352                g_smoke[count].structure_id = v.structure_id 
     353                g_smoke[count].software_version = v.software_version 
     354                g_smoke[count].device_id = v.device_id 
     355                g_smoke[count].is_online = v.is_online 
     356                g_smoke[count].last_connection = v.last_connection 
     357                g_smoke[count].battery_health = v.battery_health 
     358                g_smoke[count].co_alarm_state = v.co_alarm_state 
     359                g_smoke[count].smoke_alarm_state = v.smoke_alarm_state 
     360                g_smoke[count].ui_color_state = v.ui_color_state 
     361                count = count + 1 
     362            end 
     363        end 
     364        if response.devices.structures then 
     365            local count = 1 
     366            g_structures[count] = {} 
     367            for k,v in pairs(response.structures) do 
     368                g_structures[count].structure_id = v.structure_id 
     369                g_structures[count].thermostats = v.thermostats 
     370                g_structures[count].smoke_co_alarms = v.smoke_co_alarms 
     371                g_structures[count].name = v.name 
     372                g_structures[count].away = v.away 
     373                -- [[ 
     374                g_structures[count].is_online = v.is_online 
     375                g_structures[count].last_connection = v.last_connection 
     376                g_structures[count].battery_health = v.battery_health 
     377                g_structures[count].co_alarm_state = v.co_alarm_state 
     378                g_structures[count].smoke_alarm_state = v.smoke_alarm_state 
     379                g_structures[count].ui_color_state = v.ui_color_state 
     380                -- ]] 
     381                count = count + 1 
     382            end 
     383        end 
     384    end 
     385end 
     386 
     387local function loginToNest(device, username, password) 
     388     
     389    local url = "https://home.nest.com/user/login" 
     390    local curlCommand = "curl -k --data 'username=" .. g_username .. "&password=" ..g_password .. "' https://home.nest.com/user/login" 
     391    log("loginToNest", "curlCommand = " .. tostring(curlCommand)) 
     392    local stdout = io.popen(curlCommand) 
     393    local response = stdout:read("*a") 
     394    stdout:close()   
     395    log("loginToNest", "curlCommand Response = " .. tostring(response)) 
     396    local json_response = dkjson.decode(response) 
     397    local data = {} 
     398    if json_response.error then 
     399        log("loginToNest", "error = " .. json_response.error) 
     400        log("loginToNest", "description = " .. json_response.error_description) 
     401    else 
     402        data.transport_url = json_response.urls.transport_url 
     403        data.userid = json_response.userid 
     404        data.access_token = json_response.access_token 
     405    end 
     406    log("loginToNest","data.transport_url = [" .. data.transport_url .. "]" ) 
     407    log("loginToNest","data.userid = [" .. data.userid .. "]" ) 
     408    log("loginToNest","data.access_token = [" .. data.access_token .. "]" ) 
     409    url = "https://developer-api.nest.com/?auth=" .. data.access_token 
     410    log("loginToNest","URL = [" .. url .. "]" ) 
     411    curlCommand = "curl -k -L -X GET -H 'Accept: application/json '" .. url 
     412    log("loginToNest", "curlCommand2 = " .. tostring(curlCommand)) 
     413    stdout = io.popen(curlCommand) 
     414    response = stdout:read("*a") 
     415    stdout:close()   
     416    log("loginToNest", "curlCommand2 Response = " .. tostring(response)) 
     417    local json_response = dkjson.decode(response) 
     418end 
    268419--------------------------------------------------------- 
    269420---------------System Command Group---------------------- 
    270421--------------------------------------------------------- 
    271  
     422local function updateThermostatValues() 
     423    debug("updateThermostatValues","Verifying... ") 
     424    local CurrentTemperature = 0 
     425    local CurrentSetpoint = 0 
     426    local SetpointTarget = 0 
     427    local ModeStatus = "" 
     428    local CurrentHumidity = 0 
     429    for key, value in pairs(g_thermostats) do 
     430        CurrentTemperature = tostring(value["ambient_temperature_" .. temperatureScale]) 
     431        CurrentSetpoint = tostring(value["target_temperature_" .. temperatureScale]) 
     432        ModeStatus = tostring(value.hvac_mode) 
     433        CurrentHumidity = value.humidity 
     434        if ModeStatus == "heat" then 
     435            ModeStatus = "HeatOn" 
     436        elseif ModeStatus == "cool" then 
     437            ModeStatus = "CoolOn" 
     438        elseif ModeStatus == "heat-cool" then 
     439            ModeStatus = "AutoChangeOver" 
     440        elseif ModeStatus == "off" then 
     441            ModeStatus = "Off" 
     442        end 
     443         
     444        local AllSetpoints = CurrentSetpoint .. "," .. CurrentSetpoint .. ",0" 
     445        --debug("updateThermostatValues","CurrentTemperature = " .. tostring(CurrentTemperature) .. " CurrentSetpoint = " .. tostring(CurrentSetpoint) .. " AllSetpoints = " .. tostring(AllSetpoints)) 
     446        --debug("updateThermostatValues","DEVICE ID = " .. tostring(value.vera_id)) 
     447         
     448        local ModeStatusUI = luup.variable_get("urn:upnp-org:serviceId:HVAC_UserOperatingMode1", "ModeStatus", tonumber(value.vera_id)) or "" 
     449        local CurrentSetpointUI = luup.variable_get("urn:upnp-org:serviceId:TemperatureSetpoint1", "CurrentSetpoint", tonumber(value.vera_id)) or "" 
     450        local CurrentTemperatureUI = luup.variable_get("urn:upnp-org:serviceId:TemperatureSensor1", "CurrentTemperature", tonumber(value.vera_id)) or "" 
     451        local HumidityUI = luup.variable_get("urn:micasaverde-com:serviceId:HumiditySensor1", "CurrentLevel", tonumber(value.vera_id)) or "" 
     452         
     453        if ModeStatus ~= ModeStatusUI then 
     454            luup.variable_set("urn:upnp-org:serviceId:HVAC_UserOperatingMode1", "ModeStatus", ModeStatus, tonumber(value.vera_id)) 
     455        end 
     456        if CurrentSetpoint ~= CurrentSetpointUI then 
     457            luup.variable_set("urn:upnp-org:serviceId:TemperatureSetpoint1", "CurrentSetpoint", CurrentSetpoint, tonumber(value.vera_id)) 
     458            luup.variable_set("urn:upnp-org:serviceId:TemperatureSetpoint1", "AllSetpoints", AllSetpoints, tonumber(value.vera_id)) 
     459        end 
     460        if CurrentTemperature ~= CurrentTemperatureUI then 
     461            luup.variable_set("urn:upnp-org:serviceId:TemperatureSensor1", "CurrentTemperature", CurrentTemperature, tonumber(value.vera_id)) 
     462        end 
     463        if tonumber(HumidityUI) ~= CurrentHumidity then 
     464            luup.variable_set("urn:micasaverde-com:serviceId:HumiditySensor1", "CurrentLevel", CurrentHumidity ,tonumber(value.humidityDevice_id)) 
     465        end 
     466    end 
     467end 
     468 
     469local function updateSmokeValues() 
     470 
     471end 
    272472--------------------------------------------------------- 
    273473---------------Action Implementations-------------------- 
     
    277477        luup.task("Clearing...", TASK.SUCCESS, "BoschPlugin", g_taskHandle) 
    278478    end 
    279     debug("(Bosch Plugin)::(clearTask) : Clearing task... ") 
    280 end 
    281  
    282  
     479    debug("clearTask", "Clearing task... ") 
     480end 
     481 
     482function setModeTarget(device, mode) 
     483    local VeraMode = mode 
     484    if mode == "HeatOn" then  
     485        mode = "heat" 
     486    elseif mode == "CoolOn" then 
     487        mode = "cool" 
     488    elseif mode == "AutoChangeOver" then 
     489        mode = "heat-cool" 
     490    elseif mode == "Off" then 
     491        mode = "off" 
     492    end 
     493     
     494    local thermostatID = getNestDeviceID(device, g_thermostats) 
     495     
     496    --curl -v -L -X PUT "https://developer-api.nest.com/structures/g-9y-2xkHpBh1MGkVaqXOGJiKOB9MkoW1hhYyQk2vAunCK8a731jbg?auth=<AUTH_TOKEN>" -H "Content-Type: application/json" -d '{"away":"away"}' 
     497    local url = g_URL .. "/devices/thermostats/" .. tostring(thermostatID) .. "?auth=" .. nest_token 
     498    local header = "-H 'Content-Type: application/json'" 
     499    local data = "-d '{\"hvac_mode\" : \"" .. mode .."\" }'" 
     500    log("setModeTarget", "data = " .. data) 
     501    local response, response_string = nestRequest("PUT", header, url, data) 
     502    if not response then 
     503        log("setModeTarget", "ERROR : Could not set Data!") 
     504    else 
     505        log("setModeTarget", "Nest Response = " .. response_string) 
     506        luup.variable_set("urn:upnp-org:serviceId:HVAC_UserOperatingMode1", "ModeStatus", VeraMode, device) 
     507    end 
     508end 
     509 
     510function setCurrentSetpoint(device, value) 
     511    local thermostatID = getNestDeviceID(device, g_thermostats) 
     512     
     513    if tonumber(value) > 32 then 
     514        value = "32" 
     515    end 
     516    --curl -v -L -X PUT "https://developer-api.nest.com/structures/g-9y-2xkHpBh1MGkVaqXOGJiKOB9MkoW1hhYyQk2vAunCK8a731jbg?auth=<AUTH_TOKEN>" -H "Content-Type: application/json" -d '{"away":"away"}' 
     517    local url = g_URL .. "/devices/thermostats/" .. tostring(thermostatID) .. "?auth=" .. nest_token 
     518    local header = "-H 'Content-Type: application/json'" 
     519    local data = "-d '{\"target_temperature_" .. temperatureScale .. "\" :" .. tonumber(value) .. "}'" 
     520    log("setCurrentSetpoint", "data = " .. data) 
     521    local response, response_string = nestRequest("PUT", header, url, data) 
     522    if not response then 
     523        log("setCurrentSetpoint", "ERROR : Could not set Data!") 
     524    else 
     525        log("setCurrentSetpoint", "Request OK, Response = " .. response_string) 
     526        local all = luup.variable_get("urn:upnp-org:serviceId:TemperatureSetpoint1", "AllSetpoints", device) or "" 
     527        local now = luup.variable_get("urn:upnp-org:serviceId:TemperatureSetpoint1", "CurrentSetpoint", device) or "" 
     528        all = string.gsub( all, now, value, 1 ) 
     529        log("setCurrentSetpoint", "ALL = [" .. all .. "]") 
     530        luup.variable_set("urn:upnp-org:serviceId:TemperatureSetpoint1", "AllSetpoints", all, device) 
     531        luup.variable_set("urn:upnp-org:serviceId:TemperatureSetpoint1", "CurrentSetpoint", value, device) 
     532    end 
     533end 
     534 
     535function setArmed(device, value) 
     536    luup.variable_set(SID.SES, "Armed", value, device) 
     537end 
     538 
     539function setTarget(device, value) 
     540    luup.variable_set(SID.SWP, "Status", value, device) 
     541    luup.variable_set(SID.SWP, "Target", value, device) 
     542end 
     543 
     544function connectWithNest(device, username, password) 
     545    log("connectWithNest", "AM AJUNS!!!!") 
     546    loginToNest(device, username, password) 
     547end 
    283548--------------------------------------------------------- 
    284549---------------Initialization Functions------------------ 
     
    287552    for dev, attr in pairs(luup.devices) do 
    288553        if (attr.device_num_parent == device) then 
    289             local zoneNo = attr.id:match("^bosch_point_(%d+)") 
    290             local partitionNo = attr.id:match("^bosch_area_(%d+)") 
    291             local outputNo = attr.id:match("^bosch_output_(%d+)_") 
    292             for k,v in pairs(g_areas) do 
    293                 if partitionNo == tostring(v.panelID) then 
    294                     partitionNo = tostring(k) 
    295                 end 
    296             end 
    297             if (zoneNo ~= nil) then 
    298                 zoneNo = tonumber(zoneNo, 10) 
    299                 g_points[zoneNo].devId = dev 
    300             elseif (partitionNo ~= nil) then 
    301                     partitionNo = tonumber(partitionNo, 10) 
    302                     g_areas[partitionNo].devId = dev 
    303             else 
    304                 if (outputNo ~= nil) then 
    305                     outputNo = tonumber(outputNo, 10) 
    306                     for key,val in pairs(g_outputs) do 
    307                         if outputNo == tonumber(val.panelID) then 
    308                             g_outputs[key].devId = dev 
    309                         end 
     554            local thermostatID = attr.id:match("^nest_thermostat_(.+)") 
     555            local smokeID = attr.id:match("^nest_sco_(.+)") 
     556            local humidity = attr.id:match("^nest_humidity_(.+)") 
     557            if thermostatID then 
     558                for k,v in pairs(g_thermostats) do 
     559                    if thermostatID == tostring(v.device_id) then 
     560                        g_thermostats[tonumber(k)].vera_id = dev 
    310561                    end 
    311562                end 
    312563            end 
    313         end 
    314     end 
    315 end 
    316  
    317 local function appendPoints() 
    318     local count = 0 
    319     for i, v in ipairs(g_points) do 
    320         debug("(Bosch Plugin)::(appendPoints) : Appending zone ".. i ..".") 
    321         local device = getDeviceType(i) 
    322         luup.chdev.append(lug_device, g_appendPtr, "bosch_point_"..i, "Point ".. i ..": ".. v.label, device.type, device.file, nil, nil, false) 
    323         if count > 20 then 
    324             debug("(Bosch Plugin)::(appendPoints) : Possible error in generating points, more then 20 devices were generated!!!") 
    325             FLAGS.ZONES = true 
    326             return 
    327         end 
    328     end 
    329     FLAGS.ZONES = true 
    330 end 
    331  
    332 local function appendAreas() 
    333     local count = 0 
    334     for i, v in ipairs(g_areas) do 
    335         debug("(Bosch Plugin)::(appendAreas) : Appending partition ".. i ..".") 
    336         luup.chdev.append(lug_device, g_appendPtr, "bosch_area_".. v.panelID, "Area Control ".. v.panelID ..": ".. v.name, "urn:schemas-micasaverde-com:device:BoschAlarmPartition:1", "D_BoschAlarmPartition1.xml", nil, nil, false) 
     564            if smokeID then 
     565                for k,v in pairs(g_smoke) do 
     566                    if smokeID == tostring(v.device_id) then 
     567                        g_smoke[tonumber(k)].vera_id = dev 
     568                    end 
     569                end 
     570            end 
     571            if humidity then 
     572                for k,v in pairs(g_thermostats) do 
     573                    if humidity == tostring(v.device_id) then 
     574                        g_thermostats[tonumber(k)].humidityDevice_id = dev 
     575                    end 
     576                end 
     577            end 
     578        end 
     579    end 
     580end 
     581 
     582 
     583local function appendDevices() 
     584    local count  = 0 
     585    for k, v in ipairs(g_thermostats) do 
     586        debug("appendDevices", "Appending thermostat ".. v.name ..".") 
     587        luup.chdev.append(lug_device, g_appendPtr, "nest_thermostat_".. v.device_id, v.name, DEVICE_TYPES.THERMOSTAT, DEVICE_FILES.THERMOSTAT, nil, nil, false) 
     588        debug("appendDevices", "Appending Home/Away ".. v.name ..".") 
     589        luup.chdev.append(lug_device, g_appendPtr, "nest_home_away_".. v.device_id, v.name, DEVICE_TYPES.BINARY_LIGHT, DEVICE_FILES.BINARY_LIGHT, nil, nil, false) 
     590        if v.humidity then 
     591            debug("appendDevices", "Appending humidity ".. v.name ..".") 
     592            luup.chdev.append(lug_device, g_appendPtr, "nest_humidity_".. v.device_id, "Humidity - " ..v.name, DEVICE_TYPES.HUMIDITY, DEVICE_FILES.HUMIDITY, nil, "urn:micasaverde-com:serviceId:HumiditySensor1,CurrentLevel=" .. v.humidity, false) 
     593        end 
    337594        count = count + 1 
    338595        if count > 20 then 
    339             debug("(Bosch Plugin)::(appendAreas) : Possible error in generating areas, more then 20 devices were generated!!!") 
    340             FLAGS.PARTITIONS = true 
     596            debug("appendDevices", "Possible error in generating outputs, more then 20 devices were generated!!!") 
    341597            return 
    342598        end 
    343599    end 
    344     FLAGS.PARTITIONS = true 
    345 end 
    346  
    347 local function appendOutputs() 
    348     local count  = 0 
    349     for i, v in ipairs(g_outputs) do 
    350         debug("(Bosch Plugin)::(appendOutputs) : Appending output ".. v.name ..".") 
    351         luup.chdev.append(lug_device, g_appendPtr, "bosch_output_".. v.panelID .. "_" .. v.name, v.name, DEVICE_TYPES.BINARY_LIGHT, DEVICE_FILES.BINARY_LIGHT, nil, nil, false) 
     600     
     601    for k, v in ipairs(g_smoke) do 
     602        debug("appendDevices", "Appending smoke sensor ".. v.name ..".") 
     603        luup.chdev.append(lug_device, g_appendPtr, "nest_sco_".. v.device_id, v.name, DEVICE_TYPES.SMOKE_SENSOR, DEVICE_FILES.SMOKE_SENSOR, nil, nil, false) 
    352604        count = count + 1 
    353605        if count > 20 then 
    354             debug("(Bosch Plugin)::(appendOutputs) : Possible error in generating outputs, more then 20 devices were generated!!!") 
     606            debug("appendDevices", "Possible error in generating outputs, more then 20 devices were generated!!!") 
    355607            return 
    356608        end 
     
    359611 
    360612local function getInfos(device) 
    361     local debugMode = luup.variable_get(SID.BOSCH, "DebugMode", device) or "" 
     613     
     614    local flagError = false 
     615     
     616    local debugMode = luup.variable_get(SID.NEST, "DebugMode", device) or "" 
    362617    if (debugMode ~= "") then 
    363618        DEBUG_MODE = (debugMode == "1") and true or false 
    364619    else 
    365         luup.variable_set(SID.BOSCH, "DebugMode", (DEBUG_MODE and "1" or "0"), device) 
    366     end 
    367     log("(Bosch Plugin)::(getDebugMode) : Debug mode "..(DEBUG_MODE and "enabled" or "disabled")..".") 
    368  
    369     local polling_rate = luup.variable_get(SID.BOSCH, "POLLING_RATE", device) or "" 
     620        luup.variable_set(SID.NEST, "DebugMode", (DEBUG_MODE and "1" or "0"), device) 
     621    end 
     622    log("getInfos", "Debug mode "..(DEBUG_MODE and "enabled" or "disabled")..".") 
     623 
     624    local polling_rate = luup.variable_get(SID.NEST, "POLLING_RATE", device) or "" 
    370625    if (polling_rate ~= "") then 
    371626        POLLING_RATE = tonumber(polling_rate) 
    372627    else 
    373         luup.variable_set(SID.BOSCH, "POLLING_RATE", POLLING_RATE, device) 
    374     end 
    375     debug("(Bosch Plugin)::(getDebugMode) : POLLING_RATE = " .. POLLING_RATE ) 
    376      
    377     local safestorage = luup.variable_get(SID.BOSCH,"SafeStorage",lug_device) or "" 
    378     if safestorage == "" then 
    379         luup.variable_set(SID.BOSCH,"SafeStorage","0",lug_device) 
    380     end 
    381      
    382     local passcode = luup.variable_get(SID.BOSCH,"Passcode",lug_device) or "" 
    383     if passcode == "" then  
    384         luup.variable_set(SID.BOSCH,"Passcode","Bosch_Auto",lug_device) 
    385     end 
    386      
    387     local trash 
    388     ipAddress, trash, ipPort = string.match(luup.devices[device].ip, "^([%w%.%-]+)(:?(%d-))$") 
    389     if ipAddress and ipAddress ~= "" then 
    390         if ipPort==nil or ipPort == "" then 
    391             ipPort = "7700" 
    392         end 
    393         return true 
    394     else 
    395         log("(Bosch Plugin)::(getDebugMode) : ERROR : Insert IP address!") 
    396         return false 
    397     end 
    398 end 
    399  
    400  
    401 local function connectToPanel() 
    402     local retry 
    403     local i 
    404     local flagConnect = false 
    405     local flagPass = false 
    406     local passcode 
    407      
    408     local safestorage = luup.variable_get(SID.BOSCH,"SafeStorage",lug_device) or "" 
    409     if safestorage == "" then 
    410         luup.variable_set(SID.BOSCH,"SafeStorage","0",lug_device) 
    411         safestorage = "0" 
    412     end 
    413  
    414     if safestorage == "0" then 
    415         passcode = luup.variable_get(SID.BOSCH,"Passcode",lug_device) or "" 
    416         if passcode == "" then 
    417             luup.variable_set(SID.BOSCH,"Passcode","Bosch_Auto",lug_device) 
    418             log("(Bosch Plugin)::(connectToPanel) : ERROR : Password field have a default value!") 
    419             displayMessage("Password field have a default value!", TASK.ERROR) 
     628        luup.variable_set(SID.NEST, "POLLING_RATE", POLLING_RATE, device) 
     629    end 
     630    debug("getInfos", "POLLING_RATE = " .. POLLING_RATE ) 
     631     
     632    local username = luup.devices[device].user or "" 
     633    local password = luup.devices[device].pass or "" 
     634     
     635    getTemperatureScale() 
     636    log("getInfos", "Temperature Scale is = " .. temperatureScale) 
     637     
     638    if username == "" then 
     639        luup.attr_set("username","default",device) 
     640        g_username = "default" 
     641        flagError = true 
     642    else 
     643        if username == "default" then 
     644            flagError = true 
     645        else  
     646            g_username = username 
     647        end 
     648    end 
     649 
     650    if password == "" then 
     651        luup.attr_set("password","default",device) 
     652        g_password = "default" 
     653        flagError = true 
     654    else 
     655        if password == "default" then 
     656            flagError = true 
    420657        else 
    421             g_passcode = passcode 
    422             flagPass = true 
    423         end 
    424     elseif safestorage == "1" then 
    425         local file = io.open("/tmp/credential.txt") 
    426         if file then 
    427             for line in file:lines() do 
    428                 passcode = line:match('^(.-)$') 
    429             end 
    430             file:close() 
    431             if passcode then 
    432                 g_passcode = passcode 
    433                 flagPass = true 
    434             else 
    435                 log("(Bosch Plugin)::(connectToPanel) : ERROR : Please insert your passcode in file!") 
    436                 displayMessage("Please insert your passcode in file!", TASK.ERROR) 
    437             end 
    438         else 
    439             log("(Bosch Plugin)::(connectToPanel) : ERROR : Couldn't open passcode file!") 
    440             displayMessage("Couldn't open passcode file!", TASK.ERROR) 
    441         end 
    442     else 
    443         log("(Bosch Plugin)::(connectToPanel) : ERROR : Invalid SafeStorage value. Please insert a valid one(0 or 1)!") 
    444         displayMessage("Invalid SafeStorage value. Please insert a valid one(0 or 1)!", TASK.ERROR) 
    445     end 
    446  
    447     if flagPass then 
    448         for i = 1, 10 do 
    449             retry =  peer:connect(ipAddress, ipPort) 
    450             if retry then 
    451                 flagConnect = true 
    452                 break 
    453             else 
    454                 debug("(Bosch Plugin)::(connectToPanel) : ERROR : Cannot connect to panel!") 
    455             end 
    456         end 
    457         if flagConnect then 
    458             peer = assert( ssl.wrap(peer, params) ) 
    459             peer:settimeout(0.3) 
    460  
    461             local succ, err = peer:dohandshake() 
    462             while not succ do 
    463                 wait(peer, err) 
    464                 succ, err = peer:dohandshake() 
    465             end 
    466             debug("*** Handshake done ***") 
    467             local responseArray = {} 
    468             local responseString 
    469             responseString = WhatAreYou() 
    470             if responseString then 
    471                 responseArray = parse(responseString,{}) 
    472             else 
    473                 debug("(Bosch Plugin)::(connectToPanel) : ERROR : Handshake ERROR!") 
    474             end 
    475             responseString = PasscodeAndUserTypeCheck(g_passcode) 
    476             if responseString then 
    477                 responseArray = parse(responseString,{}) 
    478                 if responseArray[3] == "FE" then 
    479                     if responseArray[4] == "00" then 
    480                         log("(Bosch Plugin)::(connectToPanel) : ERROR :  Passcode and User Type Check ERROR! Another Session is opened, cannot authentify !") 
    481                         flagPasscode = false 
    482                     elseif responseArray[4] == "01" then 
    483                         log("(Bosch Plugin)::(connectToPanel) : OK :  Passcode and User Type Check OK! continuing ...") 
    484                         flagPasscode = true 
    485                     else 
    486                         log("(Bosch Plugin)::(connectToPanel) : ERROR :  Unknown Passcode and User Type Check ERROR! FE : [" .. responseArray[4] .. "]") 
    487                         flagPasscode = false 
    488                     end 
    489                 elseif responseArray[3] == "FD" then 
    490                     log("(Bosch Plugin)::(connectToPanel) : ERROR :  NAK received with error code " .. responseArray[4]) 
    491                     flagPasscode = false 
    492                 elseif responseArray[3] == "FC" then 
    493                     log("(Bosch Plugin)::(connectToPanel) : ERROR :  ACK received") 
    494                     flagPasscode = false 
    495                 else 
    496                     log("(Bosch Plugin)::(connectToPanel) : ERROR :  Unknown ERROR (we should not be here)") 
    497                     flagPasscode = false 
    498                 end 
    499             else 
    500                 log("(Bosch Plugin)::(connectToPanel) ERROR : PasscodeAndUserTypeCheck error!") 
    501             end 
    502         else 
    503             log("(Bosch Plugin)::(connectToPanel) : ERROR : Please check IP and PORT settings!") 
    504             displayMessage("Please check IP and PORT settings!", TASK.ERROR_STOP) 
    505         end 
    506     else 
    507         log("(Bosch Plugin)::(connectToPanel) : ERROR : Please check Passcode settings!") 
    508         displayMessage("Please check Passcode settings!", TASK.ERROR) 
    509     end 
    510 end 
    511  
     658            g_password = password 
     659        end 
     660    end 
     661     
     662    local token = luup.variable_get(SID.NEST, "TOKEN", device) or "" 
     663    if token ~= "" and token ~= "default" then 
     664        nest_token = token 
     665    else 
     666        luup.variable_set(SID.NEST, "TOKEN", "default", device) 
     667    end 
     668    return flagError 
     669end 
    512670 
    513671function Init(lul_device) 
    514  
    515672    lug_device = lul_device 
    516673    g_taskHandle = luup.task("Starting up...", TASK.BUSY, "Vera Connect WWN", g_taskHandle) 
     674    local continue = getInfos(lug_device) 
     675    if continue then 
     676        return false, "Username and/or password not set. Please add them in 'Advance' tab!", "Vera Connect WWN" 
     677    end 
     678    getNestData() 
     679    g_appendPtr = luup.chdev.start(lug_device) 
     680    appendDevices(lug_device) 
     681    luup.chdev.sync(lug_device, g_appendPtr) 
     682    getChildDevices(lug_device) 
     683    log("Init", "Updating thermostat values!") 
     684    updateThermostatValues() 
     685    log("Init", "Trying to start streaming and get the latest event/s!") 
     686    startStreaming() 
     687    getStreamEvents() 
     688    ------------------------------- 
     689    for i=1,#g_thermostats do 
     690        for k,v in pairs(g_thermostats[i]) do 
     691            log("Init","g_thermostats[".. i .."].[" .. tostring(k) .. "]=[" .. tostring(v) .. "]") 
     692        end 
     693    end  
     694    for i=1,#g_smoke do 
     695        for k,v in pairs(g_smoke[i]) do 
     696            log("Init","g_smoke[".. i .."].[" .. tostring(k) .. "]=[" .. tostring(v) .. "]") 
     697        end 
     698    end  
     699    for i=1,#g_structures do 
     700        for k,v in pairs(g_structures[i]) do 
     701            log("Init","g_structures[".. i .."].[" .. tostring(k) .. "]=[" .. tostring(v) .. "]") 
     702        end 
     703    end  
     704    ------------------------------ 
    517705    log( "Startup", "Startup Successful" ) 
    518706    g_taskHandle = luup.task("Startup successful.", TASK.BUSY, "Vera Connect WWN", g_taskHandle) 
    519707    luup.set_failure(0, lul_device) 
    520708    return true, "Startup successful.", "Vera Connect WWN" 
    521      
    522 end 
     709end 
  • /trunk/D_VeraConnectWWN1.json

    r1 r3  
    1515            "Position": "0", 
    1616            "TabType": "flash", 
     17            "top_navigation_tab" : 1, 
    1718            "SceneGroup":[ 
    1819                { 
     
    3536                    "ControlType": "label", 
    3637                    "Label": { 
    37                         "lang_tag": "list_zones", 
    38                         "text": "Points:" 
     38                        "lang_tag": "username_label", 
     39                        "text": "Userame : " 
    3940                    }, 
    4041                    "Display": { 
    4142                        "Top": 20, 
    42                         "Left": 70, 
     43                        "Left": 40, 
    4344                        "Width": 75, 
    4445                        "Height": 20 
     
    4748                { 
    4849                    "ControlType": "input", 
    49                     "ID": "ListVal", 
     50                    "ID": "username", 
    5051                    "Display": { 
    51                         "Top": 40, 
    52                         "Left": 70, 
     52                        "Top": 20, 
     53                        "Left": 130, 
     54                        "Width":100, 
     55                        "Height": 20 
     56                    } 
     57                }, 
     58                { 
     59                    "ControlType": "label", 
     60                    "Label": { 
     61                        "lang_tag": "password_label", 
     62                        "text": "Password : " 
     63                    }, 
     64                    "Display": { 
     65                        "Top": 50, 
     66                        "Left": 40, 
    5367                        "Width": 75, 
     68                        "Height": 20 
     69                    } 
     70                }, 
     71                { 
     72                    "ControlType": "input", 
     73                    "ID": "password", 
     74                    "Display": { 
     75                        "Top": 50, 
     76                        "Left": 130, 
     77                        "Width": 100, 
    5478                        "Height": 20 
    5579                    } 
     
    5882                    "ControlType": "button", 
    5983                    "Label": { 
    60                         "lang_tag": "button_bypass", 
    61                         "text": "Bypass" 
     84                        "lang_tag": "button_connect", 
     85                        "text": "Connect with Nest" 
    6286                    }, 
    6387                    "Display": { 
    64                         "Top": 70, 
    65                         "Left": 70, 
     88                        "Top": 80, 
     89                        "Left": 40, 
    6690                        "Width": 60, 
    6791                        "Height": 20 
     
    6993                    "Command": { 
    7094                        "Service": "urn:micasaverde-com:serviceId:VeraConnectWWN1", 
    71                         "Action": "SendBypassPoints", 
     95                        "Action": "ConnectWithNest", 
    7296                        "Parameters": [ 
    7397                            { 
    74                                 "Name": "List", 
    75                                 "ID": "ListVal" 
    76                             } 
    77                         ] 
    78                     } 
    79                 }, 
    80                 { 
    81                     "ControlType": "button", 
    82                     "Label": { 
    83                         "lang_tag": "button_activate", 
    84                         "text": "Unbypass" 
    85                     }, 
    86                     "Display": { 
    87                         "Top": 95, 
    88                         "Left": 70, 
    89                         "Width": 60, 
    90                         "Height": 20 
    91                     }, 
    92                     "Command": { 
    93                         "Service": "urn:micasaverde-com:serviceId:VeraConnectWWN1", 
    94                         "Action": "SendUnbypassPoints", 
    95                         "Parameters": [ 
     98                                "Name": "Username", 
     99                                "ID": "username" 
     100                            }, 
    96101                            { 
    97                                 "Name": "List", 
    98                                 "ID": "ListVal" 
     102                                "Name": "Password", 
     103                                "ID": "password" 
    99104                            } 
    100105                        ] 
     
    104109        }, 
    105110        { 
    106             "Label": { 
    107                 "lang_tag": "history", 
    108                 "text": "History" 
    109             }, 
    110             "Position": "0", 
    111             "TabType": "flash", 
    112             "SceneGroup":[ 
    113                 { 
    114                     "id": "1", 
    115                     "top": "1", 
    116                     "left": "0", 
    117                     "x": "1", 
    118                     "y": "1" 
    119                 } 
    120             ], 
    121             "ControlGroup": [ 
    122                 { 
    123                     "id": "1", 
    124                     "isSingle": "0", 
    125                     "scenegroup": "1" 
    126                 } 
    127             ], 
    128             "Control": [ 
    129                 { 
    130                     "ControlType": "label", 
    131                     "Label": { 
    132                         "lang_tag": "History_event_interval : ", 
    133                         "text": "History event interval:" 
    134                     }, 
    135                     "Display": { 
    136                         "Top": 20, 
    137                         "Left": 200, 
    138                         "Width": 100, 
    139                         "Height": 20 
    140                     } 
    141                 }, 
    142                 { 
    143                     "ControlType": "variable", 
    144                     "Display": { 
    145                         "Service": "urn:micasaverde-com:serviceId:VeraConnectWWN1", 
    146                         "Variable": "Interval", 
    147                         "Top": 20, 
    148                         "Left": 340, 
    149                         "Width": 75, 
    150                         "Height": 20 
    151                     } 
    152                 }, 
    153                 { 
    154                     "ControlType": "label", 
    155                     "Label": { 
    156                         "lang_tag": "start_event : ", 
    157                         "text": "Start event number:" 
    158                     }, 
    159                     "Display": { 
    160                         "Top": 45, 
    161                         "Left": 200, 
    162                         "Width": 75, 
    163                         "Height": 20 
    164                     } 
    165                 }, 
    166                 { 
    167                     "ControlType": "input", 
    168                     "ID": "startEventNo", 
    169                     "Display": { 
    170                         "Top": 70, 
    171                         "Left": 200, 
    172                         "Width": 75, 
    173                         "Height": 20 
    174                     } 
    175                 }, 
    176                 { 
    177                     "ControlType": "label", 
    178                     "Label": { 
    179                         "lang_tag": "number_of_events : ", 
    180                         "text": "Number of events:" 
    181                     }, 
    182                     "Display": { 
    183                         "Top": 45, 
    184                         "Left": 330, 
    185                         "Width": 75, 
    186                         "Height": 20 
    187                     } 
    188                 }, 
    189                 { 
    190                     "ControlType": "input", 
    191                     "ID": "numberOfEvents", 
    192                     "Display": { 
    193                         "Top": 70, 
    194                         "Left": 330, 
    195                         "Width": 75, 
    196                         "Height": 20 
    197                     } 
    198                 }, 
    199                 { 
    200                     "ControlType": "button", 
    201                     "Label": { 
    202                         "lang_tag": "get_history", 
    203                         "text": "Get History" 
    204                     }, 
    205                     "Display": { 
    206                         "Top": 100, 
    207                         "Left": 265, 
    208                         "Width": 80, 
    209                         "Height": 20 
    210                     }, 
    211                     "Command": { 
    212                         "Service": "urn:micasaverde-com:serviceId:VeraConnectWWN1", 
    213                         "Action": "GetHistory", 
    214                         "Parameters": [ 
    215                             { 
    216                                 "Name": "EventNo", 
    217                                 "ID": "numberOfEvents" 
    218                             }, 
    219                             { 
    220                                 "Name": "StartEvent", 
    221                                 "ID": "startEventNo" 
    222                             } 
    223                         ] 
    224                     } 
    225                 }, 
    226                 { 
    227                     "ControlType": "variable", 
    228                     "left": "1", 
    229                     "Display": { 
    230                         "Service": "urn:micasaverde-com:serviceId:VeraConnectWWN1", 
    231                         "Variable": "HistoryLog", 
    232                         "Top": 140, 
    233                         "Left": 200, 
    234                         "Width": 200, 
    235                         "Height": 200 
    236                     } 
    237                 } 
    238             ] 
     111          "Label": { 
     112            "lang_tag": "authorize", 
     113            "text": "Authorize" 
     114          }, 
     115          "Position": "1", 
     116          "TopNavigationTab": "1", 
     117          "TabType": "javascript", 
     118          "ScriptName": "J_VeraConnectWWN1.js", 
     119          "Function": "VeraConnectWWN.init" 
    239120        }, 
    240121        { 
     
    243124                "text": "Advanced" 
    244125            }, 
    245             "Position": "1", 
     126            "Position": "2", 
    246127            "TabType": "javascript", 
    247128            "ScriptName": "shared.js", 
  • /trunk/S_VeraConnectWWN1.xml

    r1 r3  
    2929    <actionList> 
    3030        <action> 
    31             <name>StorePinCode</name> 
     31            <name>ConnectWithNest</name> 
    3232            <argumentList> 
    3333                <argument> 
    34                     <name>PinCode</name> 
     34                    <name>Username</name> 
    3535                    <direction>in</direction> 
    36                     <relatedStateVariable>ui4</relatedStateVariable> 
     36                    <relatedStateVariable>string</relatedStateVariable> 
     37                </argument> 
     38                <argument> 
     39                    <name>Password</name> 
     40                    <direction>in</direction> 
     41                    <relatedStateVariable>string</relatedStateVariable> 
    3742                </argument> 
    3843            </argumentList> 
    3944        </action> 
    40         <action> 
    41             <name>ClearPinCode</name> 
    42             <argumentList></argumentList> 
    43         </action> 
    44         <action> 
    45             <name>ClearTask</name> 
    46             <argumentList></argumentList> 
    47         </action> 
    4845    </actionList> 
    4946</scpd> 
  • /trunk/D_VeraConnectWWN1.xml

    r1 r3  
    1818                <SCPDURL>S_VeraConnectWWN1.xml</SCPDURL> 
    1919            </service> 
     20            <service> 
     21                <Optional/> 
     22                <serviceType>urn:schemas-upnp-org:service:HVAC_FanOperatingMode:1</serviceType> 
     23                <serviceId>urn:upnp-org:serviceId:HVAC_FanOperatingMode1</serviceId> 
     24                <SCPDURL>S_HVAC_FanOperatingMode1.xml</SCPDURL> 
     25            </service> 
     26            <service> 
     27                <serviceType>urn:micasaverde-com:serviceId:HVAC_OperatingState:1</serviceType> 
     28                <serviceId>urn:micasaverde-com:serviceId:HVAC_OperatingState1</serviceId> 
     29                <SCPDURL>S_HVAC_OperatingState1.xml</SCPDURL> 
     30            </service> 
     31            <service> 
     32                <serviceType>urn:schemas-upnp-org:service:HVAC_UserOperatingMode:1</serviceType> 
     33                <serviceId>urn:upnp-org:serviceId:HVAC_UserOperatingMode1</serviceId> 
     34                <SCPDURL>S_HVAC_UserOperatingMode1.xml</SCPDURL> 
     35            </service> 
     36            <service> 
     37                <Optional/> 
     38                <serviceType>urn:schemas-upnp-org:service:FanSpeed:1</serviceType> 
     39                <serviceId>urn:upnp-org:serviceId:FanSpeed1</serviceId> 
     40                <SCPDURL>S_FanSpeed1.xml</SCPDURL> 
     41            </service> 
     42            <service> 
     43                <serviceType>urn:schemas-upnp-org:service:TemperatureSensor:1</serviceType> 
     44                <serviceId>urn:upnp-org:serviceId:TemperatureSensor1</serviceId> 
     45                <SCPDURL>S_TemperatureSensor1.xml</SCPDURL> 
     46            </service> 
     47            <service> 
     48                <serviceType>urn:schemas-upnp-org:service:TemperatureSetpoint:1</serviceType> 
     49                <serviceId>urn:upnp-org:serviceId:TemperatureSetpoint1</serviceId> 
     50                <SCPDURL>S_TemperatureSetpoint1.xml</SCPDURL> 
     51            </service> 
     52            <service> 
     53                <serviceType>urn:schemas-upnp-org:service:TemperatureSetpoint:1</serviceType> 
     54                <serviceId>urn:upnp-org:serviceId:TemperatureSetpoint1_Heat</serviceId> 
     55                <SCPDURL>S_TemperatureSetpoint1.xml</SCPDURL> 
     56            </service> 
     57            <service> 
     58                <serviceType>urn:schemas-upnp-org:service:TemperatureSetpoint:1</serviceType> 
     59                <serviceId>urn:upnp-org:serviceId:TemperatureSetpoint1_Cool</serviceId> 
     60                <SCPDURL>S_TemperatureSetpoint1.xml</SCPDURL> 
     61            </service> 
     62            <service> 
     63                <serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType> 
     64                <serviceId>urn:upnp-org:serviceId:SwitchPower1</serviceId> 
     65                <SCPDURL>S_SwitchPower1.xml</SCPDURL> 
     66            </service> 
     67            <service> 
     68                <serviceType>urn:schemas-micasaverde-com:service:EnergyMetering:1</serviceType> 
     69                <serviceId>urn:micasaverde-com:serviceId:EnergyMetering1</serviceId> 
     70                <SCPDURL>S_EnergyMetering1.xml</SCPDURL> 
     71            </service> 
     72            <service> 
     73                <serviceType>urn:schemas-micasaverde-com:service:HaDevice:1</serviceType> 
     74                <serviceId>urn:micasaverde-com:serviceId:HaDevice1</serviceId> 
     75                <SCPDURL>S_HaDevice1.xml</SCPDURL> 
     76            </service> 
    2077        </serviceList> 
    2178        <implementationList> 
  • /trunk/I_VeraConnectWWN1.xml

    r1 r3  
    44        local fc = 0 -- failure counter 
    55        function VeraConnectWWNStartup (lul_device) 
    6             luup.log( "(Vera Connect WWN)::(Startup) : Initiating" ) 
     6            luup.log( "(Vera Connect WWN)::(Startup) : Initiating..." ) 
    77            package.loaded.L_Bosch1 = nil 
    88            nestPlugin = require( "L_VeraConnectWWN1" ) 
     
    1111            updateState = nestPlugin.updateState 
    1212            setTarget = nestPlugin.setTarget 
    13             --reconnect = boschPlugin.reconnect 
     13            connectWithNest = nestPlugin.connectWithNest 
     14            pollNest = nestPlugin.pollNest 
     15            setModeTarget = nestPlugin.setModeTarget 
     16            setCurrentSetpoint = nestPlugin.setCurrentSetpoint 
     17            setMode = nestPlugin.setMode 
     18            setArmed = nestPlugin.setArmed 
     19            getStreamEvents = nestPlugin.getStreamEvents 
    1420             
    1521            return nestPlugin.Init( lul_device ) 
     
    2935            <name>SetTarget</name> 
    3036            <job> 
    31                 setTarget( lul_settings.newTargetValue, lul_device ) 
     37                setTarget(lul_device, lul_settings.newTargetValue) 
    3238            </job> 
    3339        </action> 
     
    3945            </job> 
    4046        </action> 
     47        <action> 
     48            <serviceId>urn:micasaverde-com:serviceId:VeraConnectWWN1</serviceId> 
     49            <name>ConnectWithNest</name> 
     50            <job> 
     51                connectWithNest (lul_device, lul_settings.username, lul_settings.password) 
     52            </job> 
     53        </action> 
     54        <action> 
     55            <serviceId>urn:upnp-org:serviceId:HVAC_UserOperatingMode1</serviceId> 
     56            <name>SetModeTarget</name> 
     57            <job> 
     58                setModeTarget (lul_device, lul_settings.NewModeTarget) 
     59            </job> 
     60        </action> 
     61        <action> 
     62            <serviceId>urn:upnp-org:serviceId:TemperatureSetpoint1</serviceId> 
     63            <name>SetCurrentSetpoint</name> 
     64            <job> 
     65                setCurrentSetpoint (lul_device, lul_settings.NewCurrentSetpoint) 
     66            </job> 
     67        </action> 
     68        <action> 
     69            <serviceId>urn:upnp-org:serviceId:HVAC_FanOperatingMode1</serviceId> 
     70            <name>SetMode</name> 
     71            <job> 
     72                setMode (lul_device, lul_settings.NewMode) 
     73            </job> 
     74        </action> 
    4175    </actionList> 
    4276</implementation> 
Note: See TracChangeset for help on using the changeset viewer.