Samsung Washmachine read status from json "SOLVED"  [Solved]

Easy to use, 100% Lua-based event scripting framework.

Moderator: leecollings

Tjeerd13
Posts: 34
Joined: Thursday 07 May 2015 16:57
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Assen
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by Tjeerd13 »

Updated code V1.1
*Typo row:93 weightSensing
*Row:182 Prevent error log if wm_percent.percentage = nil om some unknown reaseon

Code: Select all

-- assumpitions for Samsung Wasmachine Script V1.1
--[[
	 Dummy textdevices WM Programma,  WM Klaar om, WM aan het, WM Toerental, WM Resterend, WM Temperatuus.
 	Dummy on/of switch WM Status
 	Dummy Percentaeg WM Percentage
 	API key from  https://developer.samsung.com/smartthings
 	Deivce ID:
 	With this curl reqeust you can get all the device info from the command line (somewhere in the response look for "deviceId" ) (There is an 	space betwean Bearer and < YOUR API KEY> ! )
 	curl --location --request GET 'https://api.smartthings.com/v1/devices/' \ --header 'Authorization: Bearer <Your API KEY>'

]]--

local API = '<YOUR API>'
local Device = '<YOUR DEVICE ID>'
local scriptVar = 'wasmachine_JSON'

--Define dz Switches
local WM_STATUS =  'WM Status'  --Domoticz virtual switch ON/Off state  Washer
local WM_PERCENT = 'WM Percentage'

local LOGGING = true

return 
{
    on = 
    {
        timer = 
        {
            'every minute', -- just an example to trigger the request
        },
        
        devices =
        {
         200,               -- Just an Switch to activated the script manualy for testing.
        },
        httpResponses = 
        {
            scriptVar, -- must match with the callback passed to the openURL command
        },
    },
    
    logging = 
    { 
        level = domoticz.LOG_DEBUG,
        marker = scriptVar,
    }, 

    execute = function(dz, item)
    	local wm_status = dz.devices(WM_STATUS)
    	local wm_percent = dz.devices(WM_PERCENT)
        if item.isTimer or item.isDevice then
            dz.openURL({
                url = 'https://api.smartthings.com/v1/devices/'.. Device .. '/states',
                headers = { ['Authorization'] = 'Bearer '.. API },
                method = 'GET',
                callback = scriptVar, -- httpResponses above.
            })
            return
        elseif item.ok then
            if (item.isJSON) then -- when recognized as json then dzVents will convert it to a table for you
                rt = item.json.main
                if _G.logLevel == dz.LOG_DEBUG then -- Only when script loglevel is set to debug
                    
                    -- dump the string represenation of the complete table to log 
                    dz.utils.dumpTable(item.json) 
                
                    dz.log('\n-\nAnd now some subtables \n-\n ', dz.LOG_DEBUG)
                    dz.log('\n-\n ------------  main.data.value\n-\n', dz.LOG_DEBUG)
                    
                    --dump the string representation of the DATA table to log, The data attributes changes depending on the state of the washer. 
                    dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))  
                
                end
                
            
            
                local function codeToDutch(code)        --Convert Table_00_Course_* and Washingstate to Dutch
                        local translationcode = 
                            {
                               D0 = 'Katoen',
                               D1 = 'Eco Katoen',
                               D2 = 'Syntethisch',
                               D3 = 'Fijne Was',
                               D4 = 'Spelen+Centrifugeren',
                               D5 = 'Eco Trommelreiniging',
                               D6 = 'Beddengoed',
                               D7 = 'Outdoor',
                               D8 = 'Wol',
                               D9 = 'Donkere Kleding',
                               DA = 'Super Ecowas',
                               DB = 'Super Speed',
                               DC = '15 min Kort',
                               BA = 'Centrifugeren',
                               none = 'Niksen',
                               weightSensing = 'Wegen',
                               wash = 'Wassen',
                               rinse = 'Spoelen',
                               spin = 'Centrifugeren',
                               finish = 'Klaar',
                            }
                        return translationcode[code:gsub('Table_00_Course_','')] or translation[code]
                    end     
                local endprogram = 'Programma gereed'
                
                --Update textdevices only when status is changed to prevent too many irrelevant log rows
                local function updateTextOnlyWhenChanged( textSensorName, newText)
                    local textDevice = dz.devices(textSensorName)
                    if textDevice.text == newText then 
                        return 
                    else
                        textDevice.updateText(newText)
                    end
                end
                
                --Update percentagedevices only when status is changed to prevent too many irrelevant log rows
                local function updatePercentageOnlyWhenChanged( percentageSensorName, newPercentage)
                    local percentageDevice = dz.devices(percentageSensorName)
                    if percentageDevice.percentage == newPercentage then 
                        return 
                    else
                     --   percentage.updatePercentage(newPercentage)
                        percentageDevice.updatePercentage(newPercentage)
                    end
                end
                
                local function convertTime(dateString, offset )                             --convert the time to Hour,Minutem,second.
                        local function makeTimeStamp(dateString)
                            local pattern = '(%d+)%-(%d+)%-(%d+)%T(%d+):(%d+):(%d+)(%.*)' -- %d+ = 1 or more digits , %.* = 0 or more any character
                            local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern) -- split the string using the pattern
                            local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds})
                            return convertedTimestamp
                        end
                        return os.date('%H:%M:%S', makeTimeStamp(dateString) + offset )
                    end
                    
                    
                    local values = dz.utils.fromJSON(item.json.main.data.value)
                    local remainingTime = values.payload.remainingTime or  values.payload["x.com.samsung.da.remainingTime"] or 'not found'
                    local progressPercentage = values.payload.progressPercentage or  values.payload["x.com.samsung.da.progressPercentage"] or 'not found'
                    
                    
                    local completionTime = convertTime(rt.completionTime.value, 3600 )   --Making 1 hour ofset to get local time
                    local switch = rt.switch.value
                    local washerWaterTemperature = rt.washerWaterTemperature.value
                    local washerJobState = rt.washerJobState.value
                    local washerMode = rt.washerMode.value
                    local washerSpinLevel = rt.washerSpinLevel.value
                    
                    if switch == ('on') then                                            -- Turn on Domoitcz switches updates only when Washer is Active.
                            dz.log('Debuggg if swithc on:' ..  switch, dz.LOG_DEBUG)
                            wm_status.switchOn().checkFirst()     --turn on dz WM status switch
                            updateTextOnlyWhenChanged('WM Temperatuur', washerWaterTemperature )
                            updateTextOnlyWhenChanged('WM Aan het', codeToDutch(washerJobState))
                            updateTextOnlyWhenChanged('WM Toerental', washerSpinLevel)
                            updateTextOnlyWhenChanged('WM Resterend', remainingTime)
                            updateTextOnlyWhenChanged('WM Klaar om', completionTime)
                            updateTextOnlyWhenChanged('WM Programma', codeToDutch(washerMode)) 
                            updatePercentageOnlyWhenChanged('WM Percentage', progressPercentage)
                    else                                                                --Upate text deices with endprogram wen swithc is off
                                dz.log('Debuggg if switch off:' ..  switch, dz.LOG_DEBUG)
                                
                                wm_status.switchOff().checkFirst()
                                dz.log('washerMode if switch off:' ..  endprogram, dz.LOG_DEBUG)
                                updateTextOnlyWhenChanged('WM Temperatuur', endprogram)
                                updateTextOnlyWhenChanged('WM Aan het', endprogram)
                                updateTextOnlyWhenChanged('WM Toerental', endprogram)
                                updateTextOnlyWhenChanged('WM Resterend', endprogram)
                                updateTextOnlyWhenChanged('WM Klaar om', endprogram)
                                updateTextOnlyWhenChanged('WM Programma', endprogram)
                                updatePercentageOnlyWhenChanged('WM Percentage', 100)
                                
                     end        
                            if LOGGING then                                             
                                dz.log('\n-\nWhats happening: \n-\n ', dz.LOG_INFO)
                                dz.log('Klaar om:' .. completionTime, dz.LOG_INFO)
                                dz.log('Status:' .. switch, dz.LOG_INFO)
                                dz.log('Temperatuur:' .. washerWaterTemperature, dz.LOG_INFO)
                                dz.log('Aan het:' .. washerJobState, dz.LOG_INFO)
                                dz.log('Programma:' .. washerMode, dz.LOG_INFO)
                                dz.log('Toerental:' .. washerSpinLevel, dz.LOG_INFO)
                                dz.log('remaining time = ' .. remainingTime, dz.LOG_INFO) 
                                dz.log('progressPercentage  = ' .. progressPercentage, dz.LOG_INFO)
                                
                                if wm_percent.percentage == nil then                                            --Prevent error log if wm_percent.percentage = nil om some unknown reaseon
                                    dz.log('Percentage WM Percentage NIL', dz.LOG_INFO)
                                else    dz.log('Percentage WM Percentage = ' .. wm_percent.percentage .. '%' , dz.LOG_INFO)
                                
                                end
                            
                                dz.log('\n-\n============================== \n-\n ', dz.LOG_INFO)
                            end
                   
                
                
                
                return
            else
                dz.log('result was not recognized as a JSON', dz.LOG_ERROR)
            end
        else
            dz.log('result was not OK', dz.LOG_ERROR)
        end
        dz.log(item,dz.LOG_ERROR) -- dump all to log as one long string
    end
}
Pi3, Pi4, Pi4 for Testing, Dashticz, RFXtrx433, Nest: "Thermostat V2, V3, Hello". Honywell Lyric T6R, RFXCom, KaKu, HUE, P1, Open Zwave USB,
vlamke
Posts: 1
Joined: Sunday 10 September 2017 21:35
Target OS: -
Domoticz version:
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by vlamke »

Tjeerd13 wrote: Thursday 05 March 2020 13:56 Updated code V1.1
*Typo row:93 weightSensing
*Row:182 Prevent error log if wm_percent.percentage = nil om some unknown reaseon

Code: Select all

-- assumpitions for Samsung Wasmachine Script V1.1
--[[
	 Dummy textdevices WM Programma,  WM Klaar om, WM aan het, WM Toerental, WM Resterend, WM Temperatuus.
 	Dummy on/of switch WM Status
 	Dummy Percentaeg WM Percentage
 	API key from  https://developer.samsung.com/smartthings
 	Deivce ID:
 	With this curl reqeust you can get all the device info from the command line (somewhere in the response look for "deviceId" ) (There is an 	space betwean Bearer and < YOUR API KEY> ! )
 	curl --location --request GET 'https://api.smartthings.com/v1/devices/' \ --header 'Authorization: Bearer <Your API KEY>'

]]--

local API = '<YOUR API>'
local Device = '<YOUR DEVICE ID>'
local scriptVar = 'wasmachine_JSON'

--Define dz Switches
local WM_STATUS =  'WM Status'  --Domoticz virtual switch ON/Off state  Washer
local WM_PERCENT = 'WM Percentage'

local LOGGING = true

return 
{
    on = 
    {
        timer = 
        {
            'every minute', -- just an example to trigger the request
        },
        
        devices =
        {
         200,               -- Just an Switch to activated the script manualy for testing.
        },
        httpResponses = 
        {
            scriptVar, -- must match with the callback passed to the openURL command
        },
    },
    
    logging = 
    { 
        level = domoticz.LOG_DEBUG,
        marker = scriptVar,
    }, 

    execute = function(dz, item)
    	local wm_status = dz.devices(WM_STATUS)
    	local wm_percent = dz.devices(WM_PERCENT)
        if item.isTimer or item.isDevice then
            dz.openURL({
                url = 'https://api.smartthings.com/v1/devices/'.. Device .. '/states',
                headers = { ['Authorization'] = 'Bearer '.. API },
                method = 'GET',
                callback = scriptVar, -- httpResponses above.
            })
            return
        elseif item.ok then
            if (item.isJSON) then -- when recognized as json then dzVents will convert it to a table for you
                rt = item.json.main
                if _G.logLevel == dz.LOG_DEBUG then -- Only when script loglevel is set to debug
                    
                    -- dump the string represenation of the complete table to log 
                    dz.utils.dumpTable(item.json) 
                
                    dz.log('\n-\nAnd now some subtables \n-\n ', dz.LOG_DEBUG)
                    dz.log('\n-\n ------------  main.data.value\n-\n', dz.LOG_DEBUG)
                    
                    --dump the string representation of the DATA table to log, The data attributes changes depending on the state of the washer. 
                    dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))  
                
                end
                
            
            
                local function codeToDutch(code)        --Convert Table_00_Course_* and Washingstate to Dutch
                        local translationcode = 
                            {
                               D0 = 'Katoen',
                               D1 = 'Eco Katoen',
                               D2 = 'Syntethisch',
                               D3 = 'Fijne Was',
                               D4 = 'Spelen+Centrifugeren',
                               D5 = 'Eco Trommelreiniging',
                               D6 = 'Beddengoed',
                               D7 = 'Outdoor',
                               D8 = 'Wol',
                               D9 = 'Donkere Kleding',
                               DA = 'Super Ecowas',
                               DB = 'Super Speed',
                               DC = '15 min Kort',
                               BA = 'Centrifugeren',
                               none = 'Niksen',
                               weightSensing = 'Wegen',
                               wash = 'Wassen',
                               rinse = 'Spoelen',
                               spin = 'Centrifugeren',
                               finish = 'Klaar',
                            }
                        return translationcode[code:gsub('Table_00_Course_','')] or translation[code]
                    end     
                local endprogram = 'Programma gereed'
                
                --Update textdevices only when status is changed to prevent too many irrelevant log rows
                local function updateTextOnlyWhenChanged( textSensorName, newText)
                    local textDevice = dz.devices(textSensorName)
                    if textDevice.text == newText then 
                        return 
                    else
                        textDevice.updateText(newText)
                    end
                end
                
                --Update percentagedevices only when status is changed to prevent too many irrelevant log rows
                local function updatePercentageOnlyWhenChanged( percentageSensorName, newPercentage)
                    local percentageDevice = dz.devices(percentageSensorName)
                    if percentageDevice.percentage == newPercentage then 
                        return 
                    else
                     --   percentage.updatePercentage(newPercentage)
                        percentageDevice.updatePercentage(newPercentage)
                    end
                end
                
                local function convertTime(dateString, offset )                             --convert the time to Hour,Minutem,second.
                        local function makeTimeStamp(dateString)
                            local pattern = '(%d+)%-(%d+)%-(%d+)%T(%d+):(%d+):(%d+)(%.*)' -- %d+ = 1 or more digits , %.* = 0 or more any character
                            local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern) -- split the string using the pattern
                            local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds})
                            return convertedTimestamp
                        end
                        return os.date('%H:%M:%S', makeTimeStamp(dateString) + offset )
                    end
                    
                    
                    local values = dz.utils.fromJSON(item.json.main.data.value)
                    local remainingTime = values.payload.remainingTime or  values.payload["x.com.samsung.da.remainingTime"] or 'not found'
                    local progressPercentage = values.payload.progressPercentage or  values.payload["x.com.samsung.da.progressPercentage"] or 'not found'
                    
                    
                    local completionTime = convertTime(rt.completionTime.value, 3600 )   --Making 1 hour ofset to get local time
                    local switch = rt.switch.value
                    local washerWaterTemperature = rt.washerWaterTemperature.value
                    local washerJobState = rt.washerJobState.value
                    local washerMode = rt.washerMode.value
                    local washerSpinLevel = rt.washerSpinLevel.value
                    
                    if switch == ('on') then                                            -- Turn on Domoitcz switches updates only when Washer is Active.
                            dz.log('Debuggg if swithc on:' ..  switch, dz.LOG_DEBUG)
                            wm_status.switchOn().checkFirst()     --turn on dz WM status switch
                            updateTextOnlyWhenChanged('WM Temperatuur', washerWaterTemperature )
                            updateTextOnlyWhenChanged('WM Aan het', codeToDutch(washerJobState))
                            updateTextOnlyWhenChanged('WM Toerental', washerSpinLevel)
                            updateTextOnlyWhenChanged('WM Resterend', remainingTime)
                            updateTextOnlyWhenChanged('WM Klaar om', completionTime)
                            updateTextOnlyWhenChanged('WM Programma', codeToDutch(washerMode)) 
                            updatePercentageOnlyWhenChanged('WM Percentage', progressPercentage)
                    else                                                                --Upate text deices with endprogram wen swithc is off
                                dz.log('Debuggg if switch off:' ..  switch, dz.LOG_DEBUG)
                                
                                wm_status.switchOff().checkFirst()
                                dz.log('washerMode if switch off:' ..  endprogram, dz.LOG_DEBUG)
                                updateTextOnlyWhenChanged('WM Temperatuur', endprogram)
                                updateTextOnlyWhenChanged('WM Aan het', endprogram)
                                updateTextOnlyWhenChanged('WM Toerental', endprogram)
                                updateTextOnlyWhenChanged('WM Resterend', endprogram)
                                updateTextOnlyWhenChanged('WM Klaar om', endprogram)
                                updateTextOnlyWhenChanged('WM Programma', endprogram)
                                updatePercentageOnlyWhenChanged('WM Percentage', 100)
                                
                     end        
                            if LOGGING then                                             
                                dz.log('\n-\nWhats happening: \n-\n ', dz.LOG_INFO)
                                dz.log('Klaar om:' .. completionTime, dz.LOG_INFO)
                                dz.log('Status:' .. switch, dz.LOG_INFO)
                                dz.log('Temperatuur:' .. washerWaterTemperature, dz.LOG_INFO)
                                dz.log('Aan het:' .. washerJobState, dz.LOG_INFO)
                                dz.log('Programma:' .. washerMode, dz.LOG_INFO)
                                dz.log('Toerental:' .. washerSpinLevel, dz.LOG_INFO)
                                dz.log('remaining time = ' .. remainingTime, dz.LOG_INFO) 
                                dz.log('progressPercentage  = ' .. progressPercentage, dz.LOG_INFO)
                                
                                if wm_percent.percentage == nil then                                            --Prevent error log if wm_percent.percentage = nil om some unknown reaseon
                                    dz.log('Percentage WM Percentage NIL', dz.LOG_INFO)
                                else    dz.log('Percentage WM Percentage = ' .. wm_percent.percentage .. '%' , dz.LOG_INFO)
                                
                                end
                            
                                dz.log('\n-\n============================== \n-\n ', dz.LOG_INFO)
                            end
                   
                
                
                
                return
            else
                dz.log('result was not recognized as a JSON', dz.LOG_ERROR)
            end
        else
            dz.log('result was not OK', dz.LOG_ERROR)
        end
        dz.log(item,dz.LOG_ERROR) -- dump all to log as one long string
    end
}
Tjeerd13 thanks for your code, its working fantastic and I have made some changes below is my code:

Code: Select all

-- assumpitions for Samsung Wasmachine Script V1.1
--[[
	 Dummy textdevices WM Programma,  WM Klaar om, WM aan het, WM Toerental, WM Resterend, WM Temperatuus.
 	Dummy on/of switch WM Status
 	Dummy Percentaeg WM Percentage
 	API key from  https://developer.samsung.com/smartthings
 	Deivce ID:
 	With this curl reqeust you can get all the device info from the command line (somewhere in the response look for "deviceId" ) (There is an 	space betwean Bearer and < YOUR API KEY> ! )
 	curl --location --request GET 'https://api.smartthings.com/v1/devices/' \ --header 'Authorization: Bearer <Your API KEY>'

]]--

local API = '<YOUR API>'
local Device = '<YOUR DEVICE ID>'
local scriptVar = 'wasmachine_JSON'

--Define dz Switches
local WM_STATUS =  1537		  		--Domoticz virtual switch ON/Off state of the Washer
local WM_PERCENT = 1538				--Domoticz virtual text device Percentage of the Washer
local WM_WATER_TEMPERATURE = 1536	--Domoticz virtual text device Temperature of the Washer
local WM_JOB_STATE = 1533 			--Domoticz virtual text device Job State of the Washer
local WM_SPIN_LEVEL = 1534			--Domoticz virtual text device Spin Level of the Washer
local WM_REMAINING_TIME = 1535		--Domoticz virtual text device Remaining Time of the Washer
local WM_COMPLETION_TIME = 1532		--Domoticz virtual text device Completion Time of the Washer
local WM_MODE = 1531				--Domoticz virtual text device Mode of the Washer

local LOGGING = true

return
{
    on =
    {
        timer =
        {
            'every minute', -- just an example to trigger the request
        },
        
        devices =
        {
                        -- Just an Switch to activated the script manualy for testing.
        },
        httpResponses =
        {
            scriptVar, -- must match with the callback passed to the openURL command
        },
    },
    
    logging =
    {
        level = domoticz.LOG_DEBUG,
        marker = scriptVar,
    },

    execute = function(dz, item)
    	local wm_status = dz.devices(WM_STATUS)
    	local wm_percent = dz.devices(WM_PERCENT)
        if item.isTimer or item.isDevice then
            dz.openURL({
                url = 'https://api.smartthings.com/v1/devices/'.. Device .. '/states',
                headers = { ['Authorization'] = 'Bearer '.. API },
                method = 'GET',
                callback = scriptVar, -- httpResponses above.
            })
            return
        elseif item.ok then
            if (item.isJSON) then -- when recognized as json then dzVents will convert it to a table for you
                rt = item.json.main
                if _G.logLevel == dz.LOG_DEBUG then -- Only when script loglevel is set to debug
                    
                    -- dump the string represenation of the complete table to log
                    dz.utils.dumpTable(item.json)
                
                    dz.log('\n-\nAnd now some subtables \n-\n ', dz.LOG_DEBUG)
                    dz.log('\n-\n ------------  main.data.value\n-\n', dz.LOG_DEBUG)
                    
                    --dump the string representation of the DATA table to log, The data attributes changes depending on the state of the washer.
                    dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))
                
                end
                
                local function codeToDutch(code)        --Convert Table_00_Course_* and Washingstate to Dutch
                        local translationcode =
                            {
                               D0 = 'Katoen',
                               D1 = 'Eco Katoen',
                               D2 = 'Syntethisch',
                               D3 = 'Fijne Was',
                               D4 = 'Spelen+Centrifugeren',
                               D5 = 'Eco Trommelreiniging',
                               D6 = 'Beddengoed',
                               D7 = 'Outdoor',
                               D8 = 'Wol',
                               D9 = 'Donkere Kleding',
                               DA = 'Super Ecowas',
                               DB = 'Super Speed',
                               DC = '15 min Kort',
                               BA = 'Centrifugeren',
                               none = 'Niksen',
                               weightSensing = 'Wegen',
                               wash = 'Wassen',
                               rinse = 'Spoelen',
                               spin = 'Centrifugeren',
                               finish = 'Klaar',
							   endprogram = 'Programma gereed'
                            }
                        return translationcode[code:gsub('Table_00_Course_','')] or translation[code]
                    end
                
                --Update textdevices only when status is changed to prevent too many irrelevant log rows
                local function updateTextOnlyWhenChanged( textSensorName, newText)
                    local textDevice = dz.devices(textSensorName)
                    if textDevice.text == newText then
                        return
                    else
                        textDevice.updateText(newText)
                    end
                end
                
                --Update percentagedevices only when status is changed to prevent too many irrelevant log rows
                local function updatePercentageOnlyWhenChanged( percentageSensorName, newPercentage)
                    local percentageDevice = dz.devices(percentageSensorName)
                    if percentageDevice.percentage == newPercentage then 
                        return
                    else
                     --   percentage.updatePercentage(newPercentage)
                        percentageDevice.updatePercentage(newPercentage)
                    end
                end
                
                local function convertTime(dateString, offset )                             --convert the time to Hour,Minutem,second.
                        local function makeTimeStamp(dateString)
                            local pattern = '(%d+)%-(%d+)%-(%d+)%T(%d+):(%d+):(%d+)(%.*)' -- %d+ = 1 or more digits , %.* = 0 or more any character
                            local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern) -- split the string using the pattern
                            local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds})
                            return convertedTimestamp
                        end
                        return os.date('%H:%M:%S', makeTimeStamp(dateString) + offset )
                    end
                    
                    local values = dz.utils.fromJSON(item.json.main.data.value)
                    local remainingTime = values.payload.remainingTime or  values.payload["x.com.samsung.da.remainingTime"] or 'not found'
                    local progressPercentage = values.payload.progressPercentage or  values.payload["x.com.samsung.da.progressPercentage"] or 'not found'
                    
                    local completionTime = convertTime(rt.completionTime.value, 3600 )   --Making 1 hour ofset to get local time
                    local switch = rt.switch.value
                    local washerWaterTemperature = rt.washerWaterTemperature.value
                    local washerJobState = rt.washerJobState.value
                    local washerMode = rt.washerMode.value
                    local washerSpinLevel = rt.washerSpinLevel.value
                    
                    if switch == ('on') then                                            -- Turn on Domoitcz switches updates only when Washer is Active.
                            dz.log('Debuggg if swithc on:' ..  switch, dz.LOG_DEBUG)
                            wm_status.switchOn().checkFirst()     --turn on dz WM status switch
                            updateTextOnlyWhenChanged(WM_WATER_TEMPERATURE, washerWaterTemperature)
                            updateTextOnlyWhenChanged(WM_JOB_STATE, codeToDutch(washerJobState))
                            updateTextOnlyWhenChanged(WM_SPIN_LEVEL, washerSpinLevel)
                            updateTextOnlyWhenChanged(WM_REMAINING_TIME, remainingTime)
                            updateTextOnlyWhenChanged(WM_COMPLETION_TIME, completionTime)
                            updateTextOnlyWhenChanged(WM_MODE, codeToDutch(washerMode)) 
                            updatePercentageOnlyWhenChanged(WM_PERCENT, progressPercentage)
                    else                                                                --Upate text deices with endprogram wen swithc is off
                                dz.log('Debuggg if switch off:' ..  switch, dz.LOG_DEBUG)
                                
                                wm_status.switchOff().checkFirst()
                                dz.log('The washerMode if switch off:' ..  codeToDutch('endprogram'), dz.LOG_DEBUG)
                                updateTextOnlyWhenChanged(WM_WATER_TEMPERATURE, codeToDutch('endprogram'))
                                updateTextOnlyWhenChanged(WM_JOB_STATE, codeToDutch('endprogram'))
                                updateTextOnlyWhenChanged(WM_SPIN_LEVEL, codeToDutch('endprogram'))
                                updateTextOnlyWhenChanged(WM_REMAINING_TIME, codeToDutch('endprogram'))
                                updateTextOnlyWhenChanged(WM_COMPLETION_TIME, codeToDutch('endprogram'))
                                updateTextOnlyWhenChanged(WM_MODE, codeToDutch('endprogram'))
                                updatePercentageOnlyWhenChanged(WM_PERCENT, 100)
                                
                     end        
                            if LOGGING then
                                dz.log('\n-\nWhats happening: \n-\n ', dz.LOG_INFO)
                                dz.log('Ready to:' .. completionTime, dz.LOG_INFO)
                                dz.log('Status:' .. switch, dz.LOG_INFO)
                                dz.log('Temperature:' .. washerWaterTemperature, dz.LOG_INFO)
                                dz.log('Job State:' .. washerJobState, dz.LOG_INFO)
                                dz.log('Program:' .. washerMode, dz.LOG_INFO)
                                dz.log('Rpm:' .. washerSpinLevel, dz.LOG_INFO)
                                dz.log('Remaining Time = ' .. remainingTime, dz.LOG_INFO)
                                dz.log('Progress Percentage  = ' .. progressPercentage, dz.LOG_INFO)
                                
                                if wm_percent.percentage == nil then                                            --Prevent error log if wm_percent.percentage = nil om some unknown reaseon
                                    dz.log('Percentage WM Percentage NIL', dz.LOG_INFO)
                                else    dz.log('Percentage WM Percentage = ' .. wm_percent.percentage .. '%' , dz.LOG_INFO)
                                
                                end
                            
                                dz.log('\n-\n============================== \n-\n ', dz.LOG_INFO)
                            end
                return
            else
                dz.log('The result was not recognized as a JSON', dz.LOG_ERROR)
            end
        else
            dz.log('The result was not OK', dz.LOG_ERROR)
        end
        dz.log(item,dz.LOG_ERROR) -- dump all to log as one long string
    end
}
I have modified the option to need specific the names of these sensors and replaced it with that everyone can give specific names or IDX this is set in the local.
Also I have moved the "endProgram" text to the translation table so that everyone can also translate that in there language if needed.
kulderzipke
Posts: 3
Joined: Tuesday 27 October 2020 16:48
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by kulderzipke »

Thanks for the scripts, but i can you help me find the API-Key from https://developer.samsung.com/smartthings?
I can not find it?
kulderzipke
Posts: 3
Joined: Tuesday 27 October 2020 16:48
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by kulderzipke »

How can I find the Api-Key that is needed to get this script running?
Can someone help me were to click on the website: https://developer.samsung.com/smartthings to retreive the Api-Key.
kulderzipke
Posts: 3
Joined: Tuesday 27 October 2020 16:48
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by kulderzipke »

I see. had to make an account om developers site of Samsung.
Than i got a attempt to index field 'washerMode' (a nil value) error.
Fixed it by checking the logfile, if there was a new name for WasherMode, this is changed by WasherCycle.
Can be that you have to check the variables and change the Script with new names....
Finally I got it to work
Thanks for the scripting
Tjeerd13
Posts: 34
Joined: Thursday 07 May 2015 16:57
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Assen
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by Tjeerd13 »

Version 2.0 of the working script:
Some lite changes:
WasherMode changed to WaherCycle (WHY Samsung!?)
Typo's

Code: Select all

-- assumpitions for Samsung Wasmachine Script V2.0 04-Jan-2021
--[[   Dummy textdevices WM Programma,  WM Klaar om, WM aan het, WM Toerental, WM Resterend, WM Temperatuus.
 	Dummy on/of switch WM Status
 	Dummy Percentaeg WM Percentage
 	API key from  https://developer.samsung.com/smartthings
 	Device ID from  https://smartthings.developer.samsung.com/docs/api-ref/st-api.html#operation/getDevices  i used postman to get the device. 
  	Making a get request with https://api.smartthings.com/v1/devices/ 
]]--

local API = '<YOUR API>'
local Device = <Your Local device>'
local scriptVar = 'wasmachine_JSON'

--Define dz Switches
local WM_STATUS =  'WM Status'  --Domoticz virtual switch ON/Off state  Washer
local WM_PERCENT = 'WM Percentage'

local LOGGING = true

return 
{
    on = 
    {
        timer = 
        {
            'every minute', -- just an example to trigger the request
        },
        
        devices =
        {
         200,               -- Just on Switch to activated the script manualy for testing.
        },
        httpResponses = 
        {
            scriptVar, -- must match with the callback passed to the openURL command
        },
    },
    
    logging = 
    { 
        level = domoticz.LOG_ERROR,
        marker = scriptVar,
    }, 

    execute = function(dz, item)
    	local wm_status = dz.devices(WM_STATUS)
    	local wm_percent = dz.devices(WM_PERCENT)
        if item.isTimer or item.isDevice then
            dz.openURL({
                url = 'https://api.smartthings.com/v1/devices/'.. Device .. '/states',
                headers = { ['Authorization'] = 'Bearer '.. API },
                method = 'GET',
                callback = scriptVar, -- httpResponses above.
            })
            return
        elseif item.ok then
            if (item.isJSON) then -- when recognized as json then dzVents will convert it to a table for you
                rt = item.json.main
                if _G.logLevel == dz.LOG_DEBUG then -- Only when script loglevel is set to debug
                    
                    -- dump the string represenation of the complete table to log 
                    dz.utils.dumpTable(item.json) 
                
                    dz.log('\n-\nAnd now some subtables \n-\n ', dz.LOG_DEBUG)
                    dz.log('\n-\n ------------  main.data.value\n-\n', dz.LOG_DEBUG)
                    
                    --dump the string representation of the DATA table to log, The data attributes changes depending on the state of the washer. 
                    dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))  
                
                end
                
            
            
                local function codeToDutch(code)        --Convert Table_00_Course_* and Washingstate to Dutch
                        local translationcode = 
                            {
                               D0 = 'Katoen',
                               D1 = 'Eco Katoen',
                               D2 = 'Syntethisch',
                               D3 = 'Fijne Was',
                               D4 = 'Spoelen+Centrifugeren',
                               D5 = 'ECO Trommelreiniging',
                               D6 = 'Beddengoed',
                               D7 = 'Outdoor',
                               D8 = 'Wol',
                               D9 = 'Donkere Kleding',
                               DA = 'Super Ecowas',
                               DB = 'Super Speed',
                               DC = '15 min Kort',
                               BA = 'Centrifugeren',
                               none = 'Niksen',
                               Weightsensing = 'Wegen',
                               wash = 'Wassen',
                               rinse = 'Spoelen',
                               spin = 'Centrifugeren',
                               finish = 'Klaar',
                            }
                        return translationcode[code:gsub('Table_00_Course_','')] or translation[code]
                    end     
                local endprogram = 'Programma gereed'
                
                --Update textdevices only when status is changed to prevent too many irrelevant log rows
                local function updateTextOnlyWhenChanged( textSensorName, newText)
                    local textDevice = dz.devices(textSensorName)
                    if textDevice.text == newText then 
                        return 
                    else
                        textDevice.updateText(newText)
                    end
                end
                
                --Update percentagedevices only when status is changed to prevent too many irrelevant log rows
                local function updatePercentageOnlyWhenChanged( percentageSensorName, newPercentage)
                    local percentageDevice = dz.devices(percentageSensorName)
                    if percentageDevice.percentage == newPercentage then 
                        return 
                    else
                     --   percentage.updatePercentage(newPercentage)
                        percentageDevice.updatePercentage(newPercentage)
                    end
                end
                
                local function convertTime(dateString, offset )                             --convert the time to Hour,Minutem,second.
                        local function makeTimeStamp(dateString)
                            local pattern = '(%d+)%-(%d+)%-(%d+)%T(%d+):(%d+):(%d+)(%.*)' -- %d+ = 1 or more digits , %.* = 0 or more any character
                            local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern) -- split the string using the pattern
                            local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds})
                            return convertedTimestamp
                        end
                        return os.date('%H:%M:%S', makeTimeStamp(dateString) + offset )
                    end
                    
                    
                    local values = dz.utils.fromJSON(item.json.main.data.value)
                    local remainingTime = values.payload.remainingTime or  values.payload["x.com.samsung.da.remainingTime"] or 'not found'
                    local progressPercentage = values.payload.progressPercentage or  values.payload["x.com.samsung.da.progressPercentage"] or 'not found'
               --[[ 
                    local datatest1 = values.payload["10.x.com.samsung.da.progressPercentage"] or 'test1 not found'
                    local datatest2 = values.payload["3.x.com.samsung.da.cumulativePower"] or 'test2 not found'
                    local datatest3 = values.payload["3"].rep["x.com.samsung.da.cumulativePower"] or 'test3 not found'
                    local datatest4 = values.payload["4"]["x.com.samsung.da.options"]["27"] or 'test4 not found'
                    local datatest5 = values.payload["4"].rep["x.com.samsung.da.options"]["27"] or 'test5 not found'
                    local datatest6 = values.payload["4"]["x.com.samsung.da.options"] or 'test6 not found'
                    local datatest7 = values.payload["4"].rep["x.com.samsung.da.options"]["28"] or 'test7 not found'
                    local datatest8 = values.payload["4"]["x.com.samsung.da.options"]["28"] or 'test8 not found' 
                    --]]
                    
                --     local completionTime = convertTime(rt.completionTime.value, 7200)   --Making no ofset to get local time (summerimte)
                    local completionTime = convertTime(rt.completionTime.value, 3600 )   --Making 1 hour ofset to get local time (wintertime)
                    local switch = rt.switch.value
                    local washerWaterTemperature = rt.washerWaterTemperature.value
                    local washerJobState = rt.washerJobState.value
                    local washerCycle = rt.washerCycle.value
                    local washerSpinLevel = rt.washerSpinLevel.value
                    
                    if switch == ('on') then                                            -- Turn on Domoitcz switches updates only when Washer is Active.
                            dz.log('Debuggg if swithc on:' ..  switch, dz.LOG_DEBUG)
                            wm_status.switchOn().checkFirst()     --turn on dz WM status switch
                            updateTextOnlyWhenChanged('WM Temperatuur', washerWaterTemperature )
                            updateTextOnlyWhenChanged('WM Aan het', codeToDutch(washerJobState))
                            updateTextOnlyWhenChanged('WM Toerental', washerSpinLevel)
                            updateTextOnlyWhenChanged('WM Resterend', remainingTime)
                            updateTextOnlyWhenChanged('WM Klaar om', completionTime)
                            updateTextOnlyWhenChanged('WM Programma', codeToDutch(washerCycle)) 
                            updatePercentageOnlyWhenChanged('WM Percentage', progressPercentage)
                    else                                                                --Upate text deices with endprogram wen swithc is off
                                dz.log('Debuggg if switch off:' ..  switch, dz.LOG_DEBUG)
                                
                                wm_status.switchOff().checkFirst()
                                dz.log('washerMode if switch off:' ..  endprogram, dz.LOG_DEBUG)
                                updateTextOnlyWhenChanged('WM Temperatuur', endprogram)
                                updateTextOnlyWhenChanged('WM Aan het', endprogram)
                                updateTextOnlyWhenChanged('WM Toerental', endprogram)
                                updateTextOnlyWhenChanged('WM Resterend', endprogram)
                                updateTextOnlyWhenChanged('WM Klaar om', endprogram)
                                updateTextOnlyWhenChanged('WM Programma', endprogram)
                                updatePercentageOnlyWhenChanged('WM Percentage', 100)
                                
                     end        
                            if LOGGING then                                             
                                dz.log('\n-\nWhats happening: \n-\n ', dz.LOG_INFO)
                                dz.log('Klaar om:' .. completionTime, dz.LOG_INFO)
                                dz.log('Status:' .. switch, dz.LOG_INFO)
                                dz.log('Temperatuur:' .. washerWaterTemperature, dz.LOG_INFO)
                                dz.log('Aan het:' .. washerJobState, dz.LOG_INFO)
                                dz.log('Programma:' .. washerCycle, dz.LOG_INFO)
                                dz.log('Toerental:' .. washerSpinLevel, dz.LOG_INFO)
                                dz.log('remaining time = ' .. remainingTime, dz.LOG_INFO) 
                                dz.log('progressPercentage  = ' .. progressPercentage, dz.LOG_INFO)
                           
                              
                                
                                
                                if wm_percent.percentage == nil then                                            --Prevent error log if wm_percent.percentage = nil om some unknown reaseon
                                    dz.log('Percentage WM Percentage NILL', dz.LOG_INFO)
                                else    dz.log('Percentage WM Percentage = ' .. wm_percent.percentage .. '%' , dz.LOG_INFO)
                                
                                end
                            
                                dz.log('\n-\n============================== \n-\n ', dz.LOG_INFO)
                            end
                   
                
                
                
                return
            else
                dz.log('result was not recognized as a JSON', dz.LOG_ERROR)
            end
        else
            dz.log('result was not OK', dz.LOG_ERROR)
        end
        dz.log(item,dz.LOG_ERROR) -- dump all to log as one long string
    end
}
Pi3, Pi4, Pi4 for Testing, Dashticz, RFXtrx433, Nest: "Thermostat V2, V3, Hello". Honywell Lyric T6R, RFXCom, KaKu, HUE, P1, Open Zwave USB,
billytkid
Posts: 31
Joined: Sunday 14 August 2016 9:20
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by billytkid »

Hi Tjeerd & Waaren,

I've just installed a samsung smart washing machine today so I've been giving this a go, thanks for all the efforts, amazing work and well beyond anything I'd have been able to do by myself :)

I noticed a couple of things:
1. To get the device ID rather than use a get request this seems to also be shown in the URL at (https://graph-eu01-euwest1.api.smartthi ... evice/list)
2. There were some typos in the required device names (WM Temperatuur & WM Aan het)

I've got an error in the log, do you have any ideas what this means:
2021-02-21 13:13:01.530 Error: dzVents: Error: (3.0.2) wasmachine_JSON: An error occurred when calling event handler SamsungWashing
2021-02-21 13:13:01.530 Error: dzVents: Error: (3.0.2) wasmachine_JSON: ...icz/scripts/dzVents/generated_scripts/SamsungWashing.lua:98: attempt to index a nil value (global 'translation')

By changing line 98 to be

Code: Select all

return translationcode[code:gsub('Table_00_Course_','')]

, rather than

Code: Select all

return translationcode[code:gsub('Table_00_Course_','')] or translation[code]
fixed it.


Does this matter?


Thanks again!
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by waaren »

billytkid wrote: Sunday 21 February 2021 14:13 I've just installed a samsung smart washing machine today so I've been giving this a go

I've got an error in the log, do you have any ideas what this means:
2021-02-21 13:13:01.530 Error: dzVents: Error: (3.0.2) wasmachine_JSON: An error occurred when calling event handler SamsungWashing
2021-02-21 13:13:01.530 Error: dzVents: Error: (3.0.2) wasmachine_JSON: ...icz/scripts/dzVents/generated_scripts/SamsungWashing.lua:98: attempt to index a nil value (global 'translation')

Does this matter?
it does a bit because the function will now return nil without error when it could not find the code in the translationcode table
can you change line 98
from

Code: Select all

     return translationcode[code:gsub('Table_00_Course_','')] or translation
to

Code: Select all

                local code = tostring(code)
                local translatedCode = translationcode[code:gsub('Table_00_Course_','')] or translationcode[code]
                if translatedCode == nil then 
                    dz.log('codeToDutch: Found unknown code: ' .. tostring(code),dz.LOG_ERROR )
                end
                return translatedCode or '?'
                end
and try again?
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
billytkid
Posts: 31
Joined: Sunday 14 August 2016 9:20
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by billytkid »

Hi Waaren,

Thank you for this, it now works perfectly!

I'm going to see if I can tweak this into English and will post updated code if it works.

Thanks,

Will
billytkid
Posts: 31
Joined: Sunday 14 August 2016 9:20
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by billytkid »

Hi Tjeerd & Waaren,

I've just had a further play with this and have made some minor changes but IMHO make it easier to setup for a newbie (ie me!).

Amazing work on this and I hope this can help someone else:

Code: Select all

-- SETUP YOUR API CONFIGURATION HERE --
-- API key from  https://account.smartthings.com/tokens (You'll need to register first ane ensure your machine is on the same account)
-- Device ID from  https://graph-eu01-euwest1.api.smartthings.com/device/list (click on your machine, then use the number in the URL after the last /) 

local API = 'GET YOUR API KEY FROM THE URL ABOVE'
local Device = 'GET YOUR DEVICE ID FROM THE URL ABOVE'

-- CREATE YOUR OWN OUTPUTS HERE --
-- Create virtual sensors in Domoticz Hardware settings that will show the output from the washing machine. 
-- Names are suggested [in square brackets], you need to input the device ID in (brackets) below. 

local WM_PROGRAM = (493) -- Virtual device showing washing machine Program [Washing - Device type = text
local WM_COMPLETION = (494) -- Virtual device showing washing cycle completion time - Device type = text
local WM_SPIN = (496) -- Virtual device showing washing spin state - Device type = text
local WM_REMAINING = (497) -- Virtual device showing time remaining on wash - Device type = text
local WM_TEMP = (498) -- Virtual device showing washing machine Temperature - Device type = text
local WM_STATUS = (499)  -- Virtual device showing washing machine On/Off - Device type = on/off switch
local WM_PERCENT = (500) -- Virtual device showing washing machine percentage - Device type = percentage
local WM_STATE = (501) -- Virtual device showing washing cycle state - Device type = text
-- ------------------------


local scriptVar = 'wasmachine_JSON'
local LOGGING = true

return 
{
    on = 
    {
        timer = 
        {
            'every minute', -- just an example to trigger the request
        },
        
        devices =
        {
         200,               -- Just on Switch to activated the script manualy for testing.
        },
        httpResponses = 
        {
            scriptVar, -- must match with the callback passed to the openURL command
        },
    },
    
    logging = 
    { 
        level = domoticz.LOG_ERROR,
        marker = scriptVar,
    }, 

    execute = function(dz, item)
    	local wm_status = dz.devices(WM_STATUS)
    	local wm_percent = dz.devices(WM_PERCENT)
        if item.isTimer or item.isDevice then
            dz.openURL({
                url = 'https://api.smartthings.com/v1/devices/'.. Device .. '/states',
                headers = { ['Authorization'] = 'Bearer '.. API },
                method = 'GET',
                callback = scriptVar, -- httpResponses above.
            })
            return
        elseif item.ok then
            if (item.isJSON) then -- when recognized as json then dzVents will convert it to a table for you
                rt = item.json.main
                if _G.logLevel == dz.LOG_DEBUG then -- Only when script loglevel is set to debug
                    
                    -- dump the string represenation of the complete table to log 
                    dz.utils.dumpTable(item.json) 
                
                    dz.log('\n-\nAnd now some subtables \n-\n ', dz.LOG_DEBUG)
                    dz.log('\n-\n ------------  main.data.value\n-\n', dz.LOG_DEBUG)
                    
                    --dump the string representation of the DATA table to log, The data attributes changes depending on the state of the washer. 
                    dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))  
                
                end
                
            
            
                local function codeToEnglish(code)        --Convert Table_00_Course_* and Washingstate to English
                        local translationcode = 
                            {
                               D0 = 'Cotton Wash',
                               D1 = 'Eco Cotton Wash',
                               D2 = 'Synthetics',
                               D3 = 'Delicates',
                               D4 = 'Rinse & Spin',
                               D5 = 'Drum Cleaning',
                               D6 = 'Bed Linnen',
                               D7 = 'Outdoor',
                               D8 = 'Wool',
                               D9 = 'Dark Wash',
                               DA = 'Super Eco Wash',
                               DB = 'Super Speed Wash',
                               DC = '15 min quick wash',
                               BA = 'Spin',
                               none = 'Nothing',
                               Weightsensing = 'Weight Sensing',
                               wash = 'Washing',
                               rinse = 'Rinsing',
                               spin = 'Spinning',
                               finish = 'Ended',
                            }
                        
                        
                        
                        
                        local code = tostring(code)
                        local translatedCode = translationcode[code:gsub('Table_00_Course_','')] or translationcode[code]
                            if translatedCode == nil then 
                                  dz.log('codeToEnglish: Found unknown code: ' .. tostring(code),dz.LOG_ERROR )
                         end
                        return translatedCode or '?'
                    end     
                local endprogram = 'No active program'
                
                --Update textdevices only when status is changed to prevent too many irrelevant log rows
                local function updateTextOnlyWhenChanged( textSensorName, newText)
                    local textDevice = dz.devices(textSensorName)
                    if textDevice.text == newText then 
                        return 
                    else
                        textDevice.updateText(newText)
                    end
                end
                
                --Update percentagedevices only when status is changed to prevent too many irrelevant log rows
                local function updatePercentageOnlyWhenChanged( percentageSensorName, newPercentage)
                    local percentageDevice = dz.devices(percentageSensorName)
                    if percentageDevice.percentage == newPercentage then 
                        return 
                    else
                     --   percentage.updatePercentage(newPercentage)
                        percentageDevice.updatePercentage(newPercentage)
                    end
                end
                
                local function convertTime(dateString, offset )                             --convert the time to Hour,Minutem,second.
                        local function makeTimeStamp(dateString)
                            local pattern = '(%d+)%-(%d+)%-(%d+)%T(%d+):(%d+):(%d+)(%.*)' -- %d+ = 1 or more digits , %.* = 0 or more any character
                            local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern) -- split the string using the pattern
                            local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds})
                            return convertedTimestamp
                        end
                        return os.date('%H:%M:%S', makeTimeStamp(dateString) + offset )
                    end
                    
                    
                    local values = dz.utils.fromJSON(item.json.main.data.value)
                    local remainingTime = values.payload.remainingTime or  values.payload["x.com.samsung.da.remainingTime"] or 'not found'
                    local progressPercentage = values.payload.progressPercentage or  values.payload["x.com.samsung.da.progressPercentage"] or 'not found'
               --[[ 
                    local datatest1 = values.payload["10.x.com.samsung.da.progressPercentage"] or 'test1 not found'
                    local datatest2 = values.payload["3.x.com.samsung.da.cumulativePower"] or 'test2 not found'
                    local datatest3 = values.payload["3"].rep["x.com.samsung.da.cumulativePower"] or 'test3 not found'
                    local datatest4 = values.payload["4"]["x.com.samsung.da.options"]["27"] or 'test4 not found'
                    local datatest5 = values.payload["4"].rep["x.com.samsung.da.options"]["27"] or 'test5 not found'
                    local datatest6 = values.payload["4"]["x.com.samsung.da.options"] or 'test6 not found'
                    local datatest7 = values.payload["4"].rep["x.com.samsung.da.options"]["28"] or 'test7 not found'
                    local datatest8 = values.payload["4"]["x.com.samsung.da.options"]["28"] or 'test8 not found' 
                    --]]
                    
                --     local completionTime = convertTime(rt.completionTime.value, 7200)   --Making no ofset to get local time (summerimte)
                    local completionTime = convertTime(rt.completionTime.value, 3600 )   --Making 1 hour ofset to get local time (wintertime)
                    local switch = rt.switch.value
                    local washerWaterTemperature = rt.washerWaterTemperature.value
                    local washerJobState = rt.washerJobState.value
                    local washerCycle = rt.washerCycle.value
                    local washerSpinLevel = rt.washerSpinLevel.value
                    
                    if switch == ('on') then                                            -- Turn on Domoitcz switches updates only when Washer is Active.
                            dz.log('Debuggg if swithc on:' ..  switch, dz.LOG_DEBUG)
                            wm_status.switchOn().checkFirst()     --turn on dz WM status switch
                            updateTextOnlyWhenChanged(WM_TEMP, washerWaterTemperature )
                            updateTextOnlyWhenChanged(WM_STATE, codeToEnglish(washerJobState))
                            updateTextOnlyWhenChanged(WM_SPIN, washerSpinLevel)
                            updateTextOnlyWhenChanged(WM_REMAINING, remainingTime)
                            updateTextOnlyWhenChanged(WM_COMPLETION, completionTime)
                            updateTextOnlyWhenChanged(WM_PROGRAM, codeToEnglish(washerCycle)) 
                            updatePercentageOnlyWhenChanged(WM_PERCENT, progressPercentage)
                    else                                                                --Upate text devices with endprogram wen swithc is off
                                dz.log('Debuggg if switch off:' ..  switch, dz.LOG_DEBUG)
                                
                                wm_status.switchOff().checkFirst()
                                dz.log('washerMode if switch off:' ..  endprogram, dz.LOG_DEBUG)
                                updateTextOnlyWhenChanged(WM_TEMP, endprogram)
                                updateTextOnlyWhenChanged(WM_STATE, endprogram)
                                updateTextOnlyWhenChanged(WM_SPIN, endprogram)
                                updateTextOnlyWhenChanged(WM_REMAINING, endprogram)
                                updateTextOnlyWhenChanged(WM_COMPLETION, endprogram)
                                updateTextOnlyWhenChanged(WM_PROGRAM, endprogram)
                                updatePercentageOnlyWhenChanged(WM_PERCENT, 100)
                                
                     end        
                            if LOGGING then                                             
                                dz.log('\n-\nWhats happening: \n-\n ', dz.LOG_INFO)
                                dz.log('Completion Time:' .. completionTime, dz.LOG_INFO)
                                dz.log('Status:' .. switch, dz.LOG_INFO)
                                dz.log('Temperature:' .. washerWaterTemperature, dz.LOG_INFO)
                                dz.log('State:' .. washerJobState, dz.LOG_INFO)
                                dz.log('Program:' .. washerCycle, dz.LOG_INFO)
                                dz.log('Spin Speed:' .. washerSpinLevel, dz.LOG_INFO)
                                dz.log('Remaining Time = ' .. remainingTime, dz.LOG_INFO) 
                                dz.log('ProgressPercentage  = ' .. progressPercentage, dz.LOG_INFO)
                           
                              
                                
                                
                                if wm_percent.percentage == nil then                                            --Prevent error log if wm_percent.percentage = nil om some unknown reaseon
                                    dz.log('Percentage WM Percentage NILL', dz.LOG_INFO)
                                else    dz.log('Percentage WM Percentage = ' .. wm_percent.percentage .. '%' , dz.LOG_INFO)
                                
                                end
                            
                                dz.log('\n-\n============================== \n-\n ', dz.LOG_INFO)
                            end
                   
                
                
                
                return
            else
                dz.log('result was not recognized as a JSON', dz.LOG_ERROR)
            end
        else
            dz.log('result was not OK', dz.LOG_ERROR)
        end
        dz.log(item,dz.LOG_ERROR) -- dump all to log as one long string
    end
}


Robinjoo94
Posts: 21
Joined: Saturday 25 May 2019 19:06
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.1
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by Robinjoo94 »

Hi all on this topic.
I have purchased two Samsung Washing machines which were installed yesterday (one dryer actually). I would like to thank anyone who contributed to these scripts. I have both the washing machine as the dryer working with similar scripts! Happy days....
Things I stumbled upon:
1. These are dzVents scripts, not bare lua
2. Dryer has completely different JSON structure, logging with the present logging feutures was not working so removed them competely

I have added some more translation stuff, and removed non-working logging rules as explained above.
I would like to share my contribution here, feel free to re-add the parts that you like!
I hope the isdst (Is Daylight Saving Time) implementation is working, so far it does on my setup.
Furthermore I changed the script so it should not crash when you add less dummy devices since you like to (untested).

P.s. I did a cleanup of the code structure, since, well, I am a software developer with some OCD ;)

Code for the washing machine:

Code: Select all

-- SETUP YOUR API CONFIGURATION HERE --
-- API key from  https://account.smartthings.com/tokens (You'll need to register first and ensure your machine is on the same account)
-- Device ID from  https://graph-eu01-euwest1.api.smartthings.com/device/list (click on your machine, then use the number in the URL after the last /) 

local API = 'GET YOUR API KEY FROM THE URL ABOVE'
local Device = 'GET YOUR DEVICE ID FROM THE URL ABOVE'

-- CREATE YOUR OWN OUTPUTS HERE --
-- Create virtual sensors in Domoticz Hardware settings that will show the output from the washing machine. 
-- Names are suggested [in square brackets], you need to input the device ID in (brackets) below. 

local WM_TEST_SWITCH = (200)  -- Virtual on switch to activated the script manually for testing.
local WM_PROGRAM = (493) -- Virtual device showing washing machine Program [Washing - Device type = text
local WM_COMPLETION = (494) -- Virtual device showing washing cycle completion time - Device type = text
local WM_SPIN = (496) -- Virtual device showing washing spin state - Device type = text
local WM_REMAINING = (497) -- Virtual device showing time remaining on wash - Device type = text
local WM_TEMP = (498) -- Virtual device showing washing machine Temperature - Device type = text
local WM_STATUS = (499)  -- Virtual device showing washing machine On/Off - Device type = on/off switch
local WM_PERCENT = (500) -- Virtual device showing washing machine percentage - Device type = percentage
local WM_STATE = (501) -- Virtual device showing washing cycle state - Device type = text

-- ------------------------

local scriptVar = 'WashingMachine'
local LOGGING = true

--Convert Table_00_Course_* and WashingState to English
local function codeToEnglish(dz, code)
	local translationcode = 
		{
		   Table_00_Course_D0 = 'Cotton Wash',
		   Table_00_Course_D1 = 'Eco Cotton Wash',
		   Table_00_Course_D2 = 'Synthetics',
		   Table_00_Course_D3 = 'Delicates',
		   Table_00_Course_D4 = 'Rinse & Spin',
		   Table_00_Course_D5 = 'Drum Cleaning',
		   Table_00_Course_D6 = 'Bed Linnen',
		   Table_00_Course_D7 = 'Outdoor',
		   Table_00_Course_D8 = 'Wool',
		   Table_00_Course_D9 = 'Dark Wash',
		   Table_00_Course_DA = 'Super Eco Wash',
		   Table_00_Course_DB = 'Super Speed Wash',
		   Table_00_Course_DC = '15\' Quick Wash',
		   Table_00_Course_BA = 'Spin',
		   Table_02_Course_1B = 'Cotton',
		   Table_02_Course_1C = 'Eco 40-60',
		   Table_02_Course_1D = 'Super Speed Wash',
		   Table_02_Course_1E = '15\' Quick Wash',
		   Table_02_Course_1F = 'Intense Cold',
		   Table_02_Course_20 = 'Hygenic Steam',
		   Table_02_Course_21 = 'Colored Wash',
		   Table_02_Course_22 = 'Wool',
		   Table_02_Course_23 = 'Outdoor',
		   Table_02_Course_24 = 'Bed Linnen',
		   Table_02_Course_25 = 'Syntetic',
		   Table_02_Course_26 = 'Delicates',
		   Table_02_Course_27 = 'Rinse & Spin',
		   Table_02_Course_28 = 'Drain & Spin',
		   Table_02_Course_29 = 'Drum Cleaning',
		   Table_02_Course_2A = 'Jeans',
		   Table_02_Course_2B = 'All Wash',
		   Table_02_Course_2D = 'Silent Wash',
		   Table_02_Course_2E = 'Baby Clothes',
		   Table_02_Course_2F = 'Sportswear',
		   Table_02_Course_30 = 'Cloudy Day',
		   Table_02_Course_32 = 'Shirts',		   
		   Table_02_Course_33 = 'Towels',
		   none = 'Nothing',
		   weightSensing = 'Weight Sensing',
		   wash = 'Washing',
		   rinse = 'Rinsing',
		   spin = 'Spinning',
		   finish = 'Ended',
		}
	
	local code = tostring(code)
	local translatedCode = translationcode[code]
	
	if translatedCode == nil then 
		dz.log('codeToEnglish: Found unknown code: ' .. tostring(code),dz.LOG_ERROR )
	end
	
	return translatedCode or '?'
end

--Update text devices only when status is changed to prevent too many irrelevant log rows
local function updateTextOnlyWhenChanged(dz, textSensorName, newText)
	if textSensorName ~= nil then
		local textDevice = dz.devices(textSensorName)
		if textDevice.text ~= newText then
			textDevice.updateText(newText)
		end
	end
end

--Update percentage devices only when status is changed to prevent too many irrelevant log rows
local function updatePercentageOnlyWhenChanged(dz, percentageSensorName, newPercentage)
	if percentageSensorName ~= nil then
		local percentageDevice = dz.devices(percentageSensorName)
		if percentageDevice.percentage ~= newPercentage then
		 --   percentage.updatePercentage(newPercentage)
			percentageDevice.updatePercentage(newPercentage)
		end
	end
end

--Convert the time to Hour,Minute,second.
local function convertTime(dateString)
	local pattern = '(%d+)%-(%d+)%-(%d+)%T(%d+):(%d+):(%d+)(%.*)' -- %d+ = 1 or more digits , %.* = 0 or more any character
	local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern) -- split the string using the pattern
	local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds, isdst = os.date("*t", os.time()).isdst})
	return os.date('%H:%M:%S', convertedTimestamp + 3600)
end

return 
{
    on = 
    {
        timer = 
        {
            'every minute', -- just an example to trigger the request
        },
        
        devices =
        {
            WM_TEST_SWITCH, -- Just on Switch to activated the script manually for testing.
        },
        httpResponses = 
        {
            scriptVar, -- must match with the callback passed to the openURL command
        },
    },
    
    logging = 
    { 
        level = domoticz.LOG_ERROR,
        marker = scriptVar,
    }, 

    execute = function(dz, item)
    	local wm_status = dz.devices(WM_STATUS)
		
        if item.isTimer or item.isDevice then
            dz.openURL({
                url = 'https://api.smartthings.com/v1/devices/'.. Device .. '/states',
                headers = { ['Authorization'] = 'Bearer '.. API },
                method = 'GET',
                callback = scriptVar, -- httpResponses above.
            })
            return
        elseif item.ok then
            if (item.isJSON) then
				-- when recognized as json then dzVents will convert it to a table for you
                rt = item.json.main
				
                local endProgram = 'No active program'
				local values = dz.utils.fromJSON(item.json.main.data.value)
				local remainingTime = values.payload.remainingTime or values.payload["x.com.samsung.da.remainingTime"] or 'not found'
				local progressPercentage = values.payload.progressPercentage or values.payload["x.com.samsung.da.progressPercentage"] or 'not found'
				local completionTime = convertTime(rt.completionTime.value)
				local switch = rt.switch.value
				local washerWaterTemperature = rt.washerWaterTemperature.value
				local washerJobState = rt.washerJobState.value
				local washerCycle = rt.washerCycle.value
				local washerSpinLevel = rt.washerSpinLevel.value
                    
				if switch == ('on') then
					-- Turn on Domoticz switches updates only when Washer is Active.
					dz.log('Debug if switch on:' ..  switch, dz.LOG_DEBUG)
					wm_status.switchOn().checkFirst()     --turn on dz WM status switch
					updateTextOnlyWhenChanged(dz, WM_TEMP, washerWaterTemperature )
					updateTextOnlyWhenChanged(dz, WM_STATE, codeToEnglish(dz, washerJobState))
					updateTextOnlyWhenChanged(dz, WM_SPIN, washerSpinLevel)
					updateTextOnlyWhenChanged(dz, WM_REMAINING, remainingTime)
					updateTextOnlyWhenChanged(dz, WM_COMPLETION, completionTime)
					updateTextOnlyWhenChanged(dz, WM_PROGRAM, codeToEnglish(dz, washerCycle)) 
					updatePercentageOnlyWhenChanged(dz, WM_PERCENT, progressPercentage)
				else
					--Update text devices with endProgram when switch is off
					dz.log('Debug if switch off:' ..  switch, dz.LOG_DEBUG)					
					wm_status.switchOff().checkFirst()
					dz.log('washerMode if switch off:' ..  endProgram, dz.LOG_DEBUG)
					updateTextOnlyWhenChanged(dz, WM_TEMP, endProgram)
					updateTextOnlyWhenChanged(dz, WM_STATE, endProgram)
					updateTextOnlyWhenChanged(dz, WM_SPIN, endProgram)
					updateTextOnlyWhenChanged(dz, WM_REMAINING, endProgram)
					updateTextOnlyWhenChanged(dz, WM_COMPLETION, endProgram)
					updateTextOnlyWhenChanged(dz, WM_PROGRAM, endProgram)
					updatePercentageOnlyWhenChanged(dz, WM_PERCENT, 100)							
				end
                
                return
            else
                dz.log('result was not recognized as a JSON', dz.LOG_ERROR)
            end
        else
            dz.log('result was not OK', dz.LOG_ERROR)
        end
        dz.log(item, dz.LOG_ERROR) -- dump all to log as one long string
    end
}
Then I have some equal code for the Dryer, I have still to do some work on the translations... :

Code: Select all

-- SETUP YOUR API CONFIGURATION HERE --
-- API key from  https://account.smartthings.com/tokens (You'll need to register first and ensure your machine is on the same account)
-- Device ID from  https://graph-eu01-euwest1.api.smartthings.com/device/list (click on your machine, then use the number in the URL after the last /) 

local API = 'GET YOUR API KEY FROM THE URL ABOVE'
local Device = 'GET YOUR DEVICE ID FROM THE URL ABOVE'

-- CREATE YOUR OWN OUTPUTS HERE --
-- Create virtual sensors in Domoticz Hardware settings that will show the output from the washing machine. 
-- Names are suggested [in square brackets], you need to input the device ID in (brackets) below. 

local DR_TEST_SWITCH = (55)  -- Virtual on switch to activated the script manually for testing.
local DR_PROGRAM = (56) -- Virtual device showing washing machine Program [Washing - Device type = text
local DR_COMPLETION = (57) -- Virtual device showing washing cycle completion time - Device type = text
local DR_REMAINING = (58) -- Virtual device showing time remaining on wash - Device type = text
local DR_STATUS = (61)  -- Virtual device showing washing machine On/Off - Device type = on/off switch
local DR_PERCENT = (62) -- Virtual device showing washing machine percentage - Device type = percentage

-- ------------------------

local scriptVar = 'Dryer'
local LOGGING = true

--Convert Table_00_Course_* and WashingState to English
local function codeToEnglish(dz, code)
	local translationcode = 
		{
		   Table_03_Course_16 = 'Cotton',
		   Table_03_Course_17 = 'Super Speed',
		   Table_03_Course_18 = 'Synthetics',
		   Table_03_Course_19 = 'Delicates',
		   Table_03_Course_1A = 'Wool',
		   Table_03_Course_1B = 'Bed Linnen',
		   Table_03_Course_1C = 'Shirts',
		   Table_03_Course_1D = 'Towels',
		   Table_03_Course_1E = 'Outdoor',
		   Table_03_Course_1F = 'Colored Wash',
		   Table_03_Course_20 = 'Iron Dry',
		   Table_03_Course_21 = 'Hygenic Care',
		   Table_03_Course_23 = '35\' Fast Dry',
		   Table_03_Course_24 = 'Cold Air',
		   Table_03_Course_25 = 'Warm Air',
		   Table_03_Course_26 = 'Air Wash',
		   Table_03_Course_27 = 'Time Program',
		   finish = 'Ended',
		}
	
	local code = tostring(code)
	local translatedCode = translationcode[code:gsub('Table_03_Course_','')] or translationcode[code]
	
	if translatedCode == nil then 
		dz.log('codeToEnglish: Found unknown code: ' .. tostring(code),dz.LOG_ERROR )
	end
	
	return translatedCode or '?'
end

--Update text devices only when status is changed to prevent too many irrelevant log rows
local function updateTextOnlyWhenChanged(dz, textSensorName, newText)
	if textSensorName ~= nil then
		local textDevice = dz.devices(textSensorName)
		if textDevice.text ~= newText then
			textDevice.updateText(newText)
		end
	end
end

--Update percentage devices only when status is changed to prevent too many irrelevant log rows
local function updatePercentageOnlyWhenChanged(dz, percentageSensorName, newPercentage)
	if percentageSensorName ~= nil then
		local percentageDevice = dz.devices(percentageSensorName)
		if percentageDevice.percentage ~= newPercentage then
		 --   percentage.updatePercentage(newPercentage)
			percentageDevice.updatePercentage(newPercentage)
		end
	end
end

--Convert the time to Hour,Minute,second.
local function convertTime(dateString)
	local pattern = '(%d+)%-(%d+)%-(%d+)%T(%d+):(%d+):(%d+)(%.*)' -- %d+ = 1 or more digits , %.* = 0 or more any character
	local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern) -- split the string using the pattern
	local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds, isdst = os.date("*t", os.time()).isdst})
	return os.date('%H:%M:%S', convertedTimestamp + 3600)
end

return 
{
    on = 
    {
        timer = 
        {
            'every minute', -- just an example to trigger the request
        },
        
        devices =
        {
            DR_TEST_SWITCH, -- Just on Switch to activated the script manually for testing.
        },
        httpResponses = 
        {
            scriptVar, -- must match with the callback passed to the openURL command
        },
    },
    
    logging = 
    { 
        level = domoticz.LOG_ERROR,
        marker = scriptVar,
    }, 

    execute = function(dz, item)
    	local dr_status = dz.devices(DR_STATUS)
		local dr_percent = dz.devices(DR_PERCENT)
		
        if item.isTimer or item.isDevice then
            dz.openURL({
                url = 'https://api.smartthings.com/v1/devices/'.. Device .. '/states',
                headers = { ['Authorization'] = 'Bearer '.. API },
                method = 'GET',
                callback = scriptVar, -- httpResponses above.
            })
            return
        elseif item.ok then
            if (item.isJSON) then
				-- when recognized as json then dzVents will convert it to a table for you
                rt = item.json.main
				
				local endProgram = 'No active program'
				local values = dz.utils.fromJSON(item.json.main.data.value)
				local remainingTime = values.payload.remainingTime or values.payload["x.com.samsung.da.remainingTime"] or 'not found'
				local progressPercentage = values.payload.progressPercentage or values.payload["x.com.samsung.da.progressPercentage"] or 'not found'
				local completionTime = convertTime(rt.completionTime.value)
				local switch = rt.switch.value
				local dryerCycle = rt.dryerCycle.value
			
				if switch == ('on') then
					-- Turn on Domoticz switches updates only when Washer is Active.
					dz.log('Debug if switch on:' ..  switch, dz.LOG_DEBUG)
					dr_status.switchOn().checkFirst()     --turn on dz WM status switch
					updateTextOnlyWhenChanged(dz, DR_REMAINING, remainingTime)
					updateTextOnlyWhenChanged(dz, DR_COMPLETION, completionTime)
					updateTextOnlyWhenChanged(dz, DR_PROGRAM, codeToEnglish(dz, dryerCycle)) 
					updatePercentageOnlyWhenChanged(dz, DR_PERCENT, progressPercentage)
				else
					--Update text devices with endProgram when switch is off
					dz.log('Debug if switch off:' ..  switch, dz.LOG_DEBUG)					
					dr_status.switchOff().checkFirst()
					dz.log('washerMode if switch off:' ..  endProgram, dz.LOG_DEBUG)
					updateTextOnlyWhenChanged(dz, DR_REMAINING, endProgram)
					updateTextOnlyWhenChanged(dz, DR_COMPLETION, endProgram)
					updateTextOnlyWhenChanged(dz, DR_PROGRAM, endProgram) 
					updatePercentageOnlyWhenChanged(dz, DR_PERCENT, 100)						
				end
                
                return
            else
                dz.log('result was not recognized as a JSON', dz.LOG_ERROR)
            end
        else
            dz.log('result was not OK', dz.LOG_ERROR)
        end
        dz.log(item, dz.LOG_ERROR) -- dump all to log as one long string
    end
}
The combined version should contain all the above!

Code: Select all

-- SETUP YOUR API CONFIGURATION HERE --
-- API key from  https://account.smartthings.com/tokens (You'll need to register first and ensure your machine is on the same account)
-- Device ID from  https://graph-eu01-euwest1.api.smartthings.com/device/list (click on your machine, then use the number in the URL after the last /) 

local API = 'GET YOUR API KEY FROM THE URL ABOVE'
local wmDevice = 'GET YOUR DEVICE ID FROM THE URL ABOVE'
local drDevice = 'GET YOUR DEVICE ID FROM THE URL ABOVE'

-- CREATE YOUR OWN OUTPUTS HERE --
-- Create virtual sensors in Domoticz Hardware settings that will show the output from the washing machine. 
-- Names are suggested [in square brackets], you need to input the device ID in (brackets) below. 

local TEST_SWITCH = (55)  -- Virtual on switch to activated the script manually for testing.

local WM_PROGRAM = (47) -- Virtual device showing washing machine Program - Device type = text
local WM_COMPLETION = (48) -- Virtual device showing washing cycle completion time - Device type = text
local WM_SPIN = (49) -- Virtual device showing washing spin state - Device type = text
local WM_REMAINING = (50) -- Virtual device showing time remaining on wash - Device type = text
local WM_TEMP = (51) -- Virtual device showing washing machine Temperature - Device type = text
local WM_STATUS = (53)  -- Virtual device showing washing machine On/Off - Device type = on/off switch
local WM_PERCENT = (54) -- Virtual device showing washing machine percentage - Device type = percentage
local WM_STATE = (52) -- Virtual device showing washing cycle state - Device type = text

local DR_PROGRAM = (56) -- Virtual device showing dryer Program - Device type = text
local DR_COMPLETION = (57) -- Virtual device showing drying cycle completion time - Device type = text
local DR_REMAINING = (58) -- Virtual device showing time remaining on wash - Device type = text
local DR_STATUS = (61)  -- Virtual device showing dryer On/Off - Device type = on/off switch
local DR_PERCENT = (62) -- Virtual device showing dryer percentage - Device type = percentage
-- ------------------------

local wmScriptVar = 'WashingMachine'
local drScriptVar = 'Dryer'
local LOGGING = true

--Convert Table_00_Course_* and WashingState to English
local function codeToEnglish(dz, code)
	local translationcode = 
		{
		   Table_00_Course_D0 = 'Cotton Wash',
		   Table_00_Course_D1 = 'Eco Cotton Wash',
		   Table_00_Course_D2 = 'Synthetics',
		   Table_00_Course_D3 = 'Delicates',
		   Table_00_Course_D4 = 'Rinse & Spin',
		   Table_00_Course_D5 = 'Drum Cleaning',
		   Table_00_Course_D6 = 'Bed Linnen',
		   Table_00_Course_D7 = 'Outdoor',
		   Table_00_Course_D8 = 'Wool',
		   Table_00_Course_D9 = 'Dark Wash',
		   Table_00_Course_DA = 'Super Eco Wash',
		   Table_00_Course_DB = 'Super Speed Wash',
		   Table_00_Course_DC = '15\' Quick Wash',
		   Table_00_Course_BA = 'Spin',
		   Table_02_Course_1B = 'Cotton',
		   Table_02_Course_1C = 'Eco 40-60',
		   Table_02_Course_1D = 'Super Speed Wash',
		   Table_02_Course_1E = '15\' Quick Wash',
		   Table_02_Course_1F = 'Intense Cold',
		   Table_02_Course_20 = 'Hygenic Steam',
		   Table_02_Course_21 = 'Colored Wash',
		   Table_02_Course_22 = 'Wool',
		   Table_02_Course_23 = 'Outdoor',
		   Table_02_Course_24 = 'Bed Linnen',
		   Table_02_Course_25 = 'Syntetic',
		   Table_02_Course_26 = 'Delicates',
		   Table_02_Course_27 = 'Rinse & Spin',
		   Table_02_Course_28 = 'Drain & Spin',
		   Table_02_Course_29 = 'Drum Cleaning',
		   Table_02_Course_2A = 'Jeans',
		   Table_02_Course_2B = 'All Wash',
		   Table_02_Course_2D = 'Silent Wash',
		   Table_02_Course_2E = 'Baby Clothes',
		   Table_02_Course_2F = 'Sportswear',
		   Table_02_Course_30 = 'Cloudy Day',
		   Table_02_Course_32 = 'Shirts',		   
		   Table_02_Course_33 = 'Towels',
		   Table_03_Course_16 = 'Cotton',
		   Table_03_Course_17 = 'Super Speed',
		   Table_03_Course_18 = 'Synthetics',
		   Table_03_Course_19 = 'Delicates',
		   Table_03_Course_1A = 'Wool',
		   Table_03_Course_1B = 'Bed Linnen',
		   Table_03_Course_1C = 'Shirts',
		   Table_03_Course_1D = 'Towels',
		   Table_03_Course_1E = 'Outdoor',
		   Table_03_Course_1F = 'Colored Wash',
		   Table_03_Course_20 = 'Iron Dry',
		   Table_03_Course_21 = 'Hygenic Care',
		   Table_03_Course_23 = '35\' Fast Dry',
		   Table_03_Course_24 = 'Cold Air',
		   Table_03_Course_25 = 'Warm Air',
		   Table_03_Course_26 = 'Air Wash',
		   Table_03_Course_27 = 'Time Program',
		   none = 'Nothing',
		   weightSensing = 'Weight Sensing',
		   wash = 'Washing',
		   rinse = 'Rinsing',
		   spin = 'Spinning',
		   finish = 'Ended',
		}
	
	local code = tostring(code)
	local translatedCode = translationcode[code]
	
	if translatedCode == nil then 
		dz.log('codeToEnglish: Found unknown code: ' .. tostring(code),dz.LOG_ERROR )
	end
	
	return translatedCode or '?'
end

--Update text devices only when status is changed to prevent too many irrelevant log rows
local function updateTextOnlyWhenChanged(dz, textSensorName, newText)
	if textSensorName ~= nil then
		local textDevice = dz.devices(textSensorName)
		if textDevice.text ~= newText then
			textDevice.updateText(newText)
		end
	end
end

--Update percentage devices only when status is changed to prevent too many irrelevant log rows
local function updatePercentageOnlyWhenChanged(dz, percentageSensorName, newPercentage)
	if percentageSensorName ~= nil then
		local percentageDevice = dz.devices(percentageSensorName)
		if percentageDevice.percentage ~= newPercentage then
		 --   percentage.updatePercentage(newPercentage)
			percentageDevice.updatePercentage(newPercentage)
		end
	end
end

--Update switch devices only when exists
local function updateSwitchOnlyWhenExists(dz, switchName, newState)
	if switchName ~= nil then
		local switch = dz.devices(switchName)
		if newState == 'ON' then
			switch.switchOn().checkFirst()
		else
			switch.switchOff().checkFirst()		
		end
	end
end

--Convert the time to Hour,Minute,second.
local function convertTime(dateString)
	local pattern = '(%d+)%-(%d+)%-(%d+)%T(%d+):(%d+):(%d+)(%.*)' -- %d+ = 1 or more digits , %.* = 0 or more any character
	local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern) -- split the string using the pattern
	local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds, isdst = os.date("*t", os.time()).isdst})
	return os.date('%H:%M:%S', convertedTimestamp + 3600)
end

return 
{
    on = 
    {
        timer = 
        {
            'every minute', -- just an example to trigger the request
        },
        
        devices =
        {
            TEST_SWITCH, -- Just on Switch to activated the script manually for testing.
        },
        httpResponses = 
        {
            wmScriptVar, -- must match with the callback passed to the openURL command
			drScriptVar, -- must match with the callback passed to the openURL command
        },
    },
    
    logging = 
    { 
        level = domoticz.LOG_ERROR,
        marker = 'SamsungWashingMachines',
    }, 

    execute = function(dz, item)
        if item.isTimer or item.isDevice then
            if wmDevice ~= nil and wmScriptVar ~= nill then 
				dz.openURL({
					url = 'https://api.smartthings.com/v1/devices/'.. wmDevice .. '/states',
					headers = { ['Authorization'] = 'Bearer '.. API },
					method = 'GET',
					callback = wmScriptVar, -- httpResponses above.
				})
			end
			if drDevice ~= nil and drScriptVar ~= nill then 
				dz.openURL({
					url = 'https://api.smartthings.com/v1/devices/'.. drDevice .. '/states',
					headers = { ['Authorization'] = 'Bearer '.. API },
					method = 'GET',
					callback = drScriptVar, -- httpResponses above.
				})
			end
            return
        elseif item.ok then
            if (item.isJSON) then
				-- when recognized as json then dzVents will convert it to a table for you
                rt = item.json.main
				
				local endProgram = 'No active program'
				local values = dz.utils.fromJSON(item.json.main.data.value)
				local remainingTime = values.payload.remainingTime or values.payload["x.com.samsung.da.remainingTime"] or 'not found'
				local progressPercentage = values.payload.progressPercentage or values.payload["x.com.samsung.da.progressPercentage"] or 'not found'
				local completionTime = convertTime(rt.completionTime.value)
				local switch = rt.switch.value
				
				-- Check whether it is a dryer or a washing machine	
				if rt.n.value == "[dryer] Samsung" then
					local dryerCycle = rt.dryerCycle.value
					
					if switch == ('on') then
						-- Turn on Domoticz switches updates only when Washer is Active.
						dz.log('Debug if switch on:' ..  switch, dz.LOG_DEBUG)
						updateSwitchOnlyWhenExists(dz, DR_STATUS, 'ON')     --turn on dz DR status switch
						updateTextOnlyWhenChanged(dz, DR_REMAINING, remainingTime)
						updateTextOnlyWhenChanged(dz, DR_COMPLETION, completionTime)
						updateTextOnlyWhenChanged(dz, DR_PROGRAM, codeToEnglish(dz, dryerCycle)) 
						updatePercentageOnlyWhenChanged(dz, DR_PERCENT, progressPercentage)
					else
						--Update text devices with endProgram when switch is off
						dz.log('Debug if switch off:' ..  switch, dz.LOG_DEBUG)					
						updateSwitchOnlyWhenExists(dz, DR_STATUS, 'OFF')     --turn off dz DR status switch
						dz.log('dryerMode if switch off:' ..  endProgram, dz.LOG_DEBUG)
						updateTextOnlyWhenChanged(dz, DR_REMAINING, endProgram)
						updateTextOnlyWhenChanged(dz, DR_COMPLETION, endProgram)
						updateTextOnlyWhenChanged(dz, DR_PROGRAM, endProgram) 
						updatePercentageOnlyWhenChanged(dz, DR_PERCENT, 100)						
					end
				else
					local washerWaterTemperature = rt.washerWaterTemperature.value
					local washerJobState = rt.washerJobState.value
					local washerCycle = rt.washerCycle.value
					local washerSpinLevel = rt.washerSpinLevel.value
					
					if switch == ('on') then
						-- Turn on Domoticz switches updates only when Washer is Active.
						dz.log('Debug if switch on:' ..  switch, dz.LOG_DEBUG)
						updateSwitchOnlyWhenExists(dz, WM_STATUS, 'ON')     --turn on dz WM status switch
						updateTextOnlyWhenChanged(dz, WM_TEMP, washerWaterTemperature )
						updateTextOnlyWhenChanged(dz, WM_STATE, codeToEnglish(dz, washerJobState))
						updateTextOnlyWhenChanged(dz, WM_SPIN, washerSpinLevel)
						updateTextOnlyWhenChanged(dz, WM_REMAINING, remainingTime)
						updateTextOnlyWhenChanged(dz, WM_COMPLETION, completionTime)
						updateTextOnlyWhenChanged(dz, WM_PROGRAM, codeToEnglish(dz, washerCycle)) 
						updatePercentageOnlyWhenChanged(dz, WM_PERCENT, progressPercentage)
					else
						--Update text devices with endProgram when switch is off
						dz.log('Debug if switch off:' ..  switch, dz.LOG_DEBUG)					
						updateSwitchOnlyWhenExists(dz, WM_STATUS, 'OFF')     --turn off dz WM status switch
						dz.log('washerMode if switch off:' ..  endProgram, dz.LOG_DEBUG)
						updateTextOnlyWhenChanged(dz, WM_TEMP, endProgram)
						updateTextOnlyWhenChanged(dz, WM_STATE, endProgram)
						updateTextOnlyWhenChanged(dz, WM_SPIN, endProgram)
						updateTextOnlyWhenChanged(dz, WM_REMAINING, endProgram)
						updateTextOnlyWhenChanged(dz, WM_COMPLETION, endProgram)
						updateTextOnlyWhenChanged(dz, WM_PROGRAM, endProgram)
						updatePercentageOnlyWhenChanged(dz, WM_PERCENT, 100)							
					end
                end
                return
            else
                dz.log('result was not recognized as a JSON', dz.LOG_ERROR)
            end
        else
            dz.log('result was not OK', dz.LOG_ERROR)
        end
        dz.log(item, dz.LOG_ERROR) -- dump all to log as one long string
    end
}
Ofcourse I have some wild plans:
1. First of all finish the translations on the dryer. Done :)
2. Then I want to combine the two into one dzVents script Done as well :)
3. Rewrite the scripts into an python plugin to have one single washing machine "widget" with all needed info :) Never done so, but a nice hobby project.
dizzeenl
Posts: 31
Joined: Wednesday 14 November 2018 23:57
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Dordrecht
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by dizzeenl »

Thank you all for this awesome code! and the further development. I now use the combination code from the last post 8-)
Unfortunately i get an error;

Code: Select all

2021-03-30 12:54:00.778 Error: dzVents: Error: (3.1.7) SamsungWashingMachines: An error occurred when calling event handler 09 SAMSUNG WASHDRY
2021-03-30 12:54:00.778 Error: dzVents: Error: (3.1.7) SamsungWashingMachines: ...scripts/dzVents/generated_scripts/09 SAMSUNG WASHDRY.lua:204: attempt to index a nil value (local 'values')
any id why this is happening to me? beside above error i dont get any other errors but the custom devices stay on default :(

Note for other beginners, be sure you use the number in the URL after the last slash if you opened the selected device and not the device network id :D
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by waaren »

dizzeenl wrote: Tuesday 30 March 2021 13:16

Code: Select all

2021-03-30 12:54:00.778 Error: dzVents: Error: (3.1.7) SamsungWashingMachines: An error occurred when calling event handler 09 SAMSUNG WASHDRY
2021-03-30 12:54:00.778 Error: dzVents: Error: (3.1.7) SamsungWashingMachines: ...scripts/dzVents/generated_scripts/09 SAMSUNG WASHDRY.lua:204: attempt to index a nil value (local 'values')
any id why this is happening to me? beside above error i dont get any other errors but the custom devices stay on default :(
Parsing item.json.main.data.value through the JSON parser is wrong and will return nil.
Can you try again after changing line 203 from

Code: Select all

local values = dz.utils.fromJSON(item.json.main.data.value)
to

Code: Select all

local values = item.json.main.data.value
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Robinjoo94
Posts: 21
Joined: Saturday 25 May 2019 19:06
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.1
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by Robinjoo94 »

waaren wrote: Tuesday 30 March 2021 14:21 Parsing item.json.main.data.value through the JSON parser is wrong and will return nil.
In my Domoticz, it is functional, when I applied the suggested changes, it showed similar errors in the log as dizzeenl had with my implementation.
Where are these differences coming from?

Furthermore, since last saterday the Daylight Saving Time started, I saw that particular bit of magic just did not do the trick, therefore some changes:

Code: Select all

--Convert the time to Hour,Minute,second.
local function convertTime(dateString)
	local pattern = '(%d+)%-(%d+)%-(%d+)%T(%d+):(%d+):(%d+)(%.*)' -- %d+ = 1 or more digits , %.* = 0 or more any character
	local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern) -- split the string using the pattern
	local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds})
	
	local tmp_time = os.time()
	local d1 = os.date("*t",  tmp_time)
	local d2 = os.date("!*t", tmp_time)
	d1.isdst = false
	local zone_diff = os.difftime(os.time(d1), os.time(d2))
	return os.date('%H:%M:%S', convertedTimestamp + zone_diff)
end
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by waaren »

Robinjoo94 wrote: Tuesday 30 March 2021 20:24 In my Domoticz, it is functional, when I applied the suggested changes, it showed similar errors in the log as dizzeenl had with my implementation.
Where are these differences coming from?
No clue but the complete JSON should already be converted to a Lua (sub)table

can you insert these commands to show what the state is of this JSON / table?

Code: Select all

dz.utils.dumpTable(item.json.main.data.value)
dz.log(item.json.main.data.value)
dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Robinjoo94
Posts: 21
Joined: Saturday 25 May 2019 19:06
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.1
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by Robinjoo94 »

waaren wrote: Tuesday 30 March 2021 20:46
Robinjoo94 wrote: Tuesday 30 March 2021 20:24 In my Domoticz, it is functional, when I applied the suggested changes, it showed similar errors in the log as dizzeenl had with my implementation.
Where are these differences coming from?
No clue but the complete JSON should already be converted to a Lua (sub)table

can you insert these commands to show what the state is of this JSON / table?

Code: Select all

dz.utils.dumpTable(item.json.main.data.value)
dz.log(item.json.main.data.value)
dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))
I got the following error on both instances of dz.utils.dumpTable. Tried both, the first and the later seperately.

Code: Select all

Error: dzVents: Error: (3.0.2) SamsungWashingMachines: /home/pi/domoticz/dzVents/runtime/Utils.lua:425: bad argument #1 to 'pairs' (table expected, got string)
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by waaren »

Robinjoo94 wrote: Wednesday 31 March 2021 10:00

Code: Select all

Error: dzVents: Error: (3.0.2) SamsungWashingMachines: /home/pi/domoticz/dzVents/runtime/Utils.lua:425: bad argument #1 to 'pairs' (table expected, got string)
Please try again after removing first of these lines

Code: Select all

dz.utils.dumpTable(item.json.main.data.value)
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Robinjoo94
Posts: 21
Joined: Saturday 25 May 2019 19:06
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.1
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by Robinjoo94 »

waaren wrote: Wednesday 31 March 2021 10:02
Robinjoo94 wrote: Wednesday 31 March 2021 10:00

Code: Select all

Error: dzVents: Error: (3.0.2) SamsungWashingMachines: /home/pi/domoticz/dzVents/runtime/Utils.lua:425: bad argument #1 to 'pairs' (table expected, got string)
Please try again after removing first of these lines

Code: Select all

dz.utils.dumpTable(item.json.main.data.value)
As mentioned, I did, so first attempt:

Code: Select all

dz.utils.dumpTable(item.json.main.data.value)
dz.log(item.json.main.data.value)
dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))
Second attempt:

Code: Select all

-- dz.utils.dumpTable(item.json.main.data.value)
dz.log(item.json.main.data.value)
dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))
Third attempt:

Code: Select all

dz.utils.dumpTable(item.json.main.data.value)
dz.log(item.json.main.data.value)
-- dz.utils.dumpTable(dz.utils.fromJSON(item.json.main.data.value))
Same error messages
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by waaren »

Robinjoo94 wrote: Wednesday 31 March 2021 10:31 Same error messages
That should not be possible as the dz.log(item.json.main.data.value) does not call the function that contains line 425 of /home/pi/domoticz/dzVents/runtime/Utils.lua

Can you share the script as it is now and the complete log?
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
dizzeenl
Posts: 31
Joined: Wednesday 14 November 2018 23:57
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Dordrecht
Contact:

Re: Samsung Washmachine read status from json "SOLVED"

Post by dizzeenl »

waaren wrote: Tuesday 30 March 2021 14:21
dizzeenl wrote: Tuesday 30 March 2021 13:16

Code: Select all

2021-03-30 12:54:00.778 Error: dzVents: Error: (3.1.7) SamsungWashingMachines: An error occurred when calling event handler 09 SAMSUNG WASHDRY
2021-03-30 12:54:00.778 Error: dzVents: Error: (3.1.7) SamsungWashingMachines: ...scripts/dzVents/generated_scripts/09 SAMSUNG WASHDRY.lua:204: attempt to index a nil value (local 'values')
any id why this is happening to me? beside above error i dont get any other errors but the custom devices stay on default :(
Parsing item.json.main.data.value through the JSON parser is wrong and will return nil.
Can you try again after changing line 203 from

Code: Select all

local values = dz.utils.fromJSON(item.json.main.data.value)
to

Code: Select all

local values = item.json.main.data.value
Unfortunately in my case the above change will still result in the same error :cry:
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest