Page 1 of 1

Upload data from Domoticz wind station to Windguru

Posted: Monday 15 February 2021 15:52
by javalin
Hello,

If you have a wind station working in Domoticz then you can connect your station using Windguru upload API with this script. Before you start uploading data, you must register your station in Windguru, choose "Other (upload API)" as station type here: https://stations.windguru.cz/register.php?id_type=16

The script must be configured with your wind station Domoticz device number, your windguru station ID and password.

Important, the wind data must be sent in knots.
Important: this script only works on linux type systems with an available md5sum executable, in my case a raspberry.

Script:

Code: Select all

--Device attributes: wind.speed, wind.gust, wind.direction, wind.directionString

return
{
    on =
    {
        devices =
        {
            295, --script is executed every change of state of the weather station, must be your wind station device number  
        },
    },

    logging =
    {
        level = domoticz.LOG_ERROR,
		marker = 'windGuru',
    },

    execute = function(dz, item)
        local wind = item                   -- your wind station device number, wind station have to work with knots units
        local uid = 'your_id'              -- your Windguru station id 
        local station_pass = 'your_pass'    -- your Windguru station password 
        local time_stamp = dz.time.dDate
        local wind_speed = dz.utils.round(wind.speed,2)
        local wind_gust = dz.utils.round(wind.gust*1.943,2)
        local wind_direction = math.floor(wind.direction)
        local wind_directionString = wind.directionString
        local mySecret = time_stamp .. uid .. station_pass
        
        local function osCommand(cmd)
            dz.log('Executing Command: ' .. cmd,dz.LOG_DEBUG)
            local fileHandle = assert(io.popen(cmd .. ' 2>&1 || echo ::ERROR::', 'r'))
            local commandOutput = assert(fileHandle:read('*a'))
            local returnTable = {fileHandle:close()}
            if commandOutput:find '::ERROR::' then     -- something went wrong
               dz.log('Error ==>> ' .. tostring(commandOutput:match('^(.*)%s+::ERROR::') or ' ... but no error message ' ) ,dz.LOG_ERROR)
            else -- all is fine!!
                dz.log('ReturnCode: ' .. returnTable[3] .. '\ncommandOutput:\n' .. commandOutput, dz.LOG_DEBUG)
            end
            return commandOutput,returnTable[3] -- rc[3] contains returnCode
        end

	local hash = osCommand('echo -n ' .. mySecret .. ' | md5sum'):match("(%w+)")
        dz.log("md5Hash of " ..mySecret .. " is " ..  hash , dz.LOG_DEBUG )
		dz.openURL( 'http://www.windguru.cz/upload/api.php?uid='..uid..'&salt='..time_stamp..'&hash=' ..
					hash..'&wind_avg='..wind_speed..'&wind_max='..wind_gust..'&wind_direction='..wind_direction)
	end
}

Data station will be uploaded via HTTP GET requests to: http://www.windguru.cz/upload/api.php
More info: https://stations.windguru.cz/upload_api.php

Kind regards.

Re: MD5 hash algorithm?

Posted: Monday 15 February 2021 16:30
by waaren
javalin wrote: Monday 15 February 2021 15:52 I am building a dzvents code to upload my wind station data to Windguru. In the process I need to create a hash calculated as MD5 to send data via HTTP GET. My doubt is, Dzvents is able to create an MD5 hash from a string?
you wil see

Code: Select all

2021-02-15 16:29:00.227 Status: dzVents: !Info: md5Hash: md5Hash of 20180214171400stationXYsupersecret is c9441d30280f4f6f4946fe2b2d360df5
when executing below script

Code: Select all

return
{
    on =
    {
        timer =
        {
            'every minute',
        },
    },

    logging =
    {
        level = domoticz.LOG_ERROR,
        marker = 'md5Hash',
    },

    execute = function(dz)

       local function osCommand(cmd)
            dz.log('Executing Command: ' .. cmd,dz.LOG_DEBUG)

            local fileHandle = assert(io.popen(cmd .. ' 2>&1 || echo ::ERROR::', 'r'))
            local commandOutput = assert(fileHandle:read('*a'))
            local returnTable = {fileHandle:close()}

            if commandOutput:find '::ERROR::' then     -- something went wrong
               dz.log('Error ==>> ' .. tostring(commandOutput:match('^(.*)%s+::ERROR::') or ' ... but no error message ' ) ,dz.LOG_ERROR)
            else -- all is fine!!
                dz.log('ReturnCode: ' .. returnTable[3] .. '\ncommandOutput:\n' .. commandOutput, dz.LOG_DEBUG)
            end

            return commandOutput,returnTable[3] -- rc[3] contains returnCode
        end


        local mySecret = '20180214171400stationXYsupersecret'

        dz.log("md5Hash of " ..mySecret .. " is " .. osCommand('echo -n ' .. mySecret .. ' | md5sum |  cut -d " " -f1'), dz.LOG_FORCE )
    end
}


Re: MD5 hash algorithm?

Posted: Monday 15 February 2021 17:05
by Toulon7559
Do you need online Hash-coding, or only a onetime Hash-coding for your password?
In the latter case plenty of tools available at internet, such as https://www.md5hashgenerator.com/

Small advantage that you keep your 'open' secret key outside your script.
:( On the other hand, using a public internet-tool for crypting is not really safe either.

Mod 16Feb2021
The inclusion of 'salt' as variable required for each upload means that this 'external' solution cannot be used:
the implementation must be included within the script.

Re: MD5 hash algorithm?

Posted: Monday 15 February 2021 19:59
by javalin
Thank you waaren works, but the 'hash function' finish creating a new line after show the hash. In others words, this is my result:

Code: Select all

 2021-02-15 18:26:10.318 Status: dzVents: Debug: md5Hash: OpenURL: url = http://www.windguru.cz/upload/api.php?uid=IDstation&salt=1613413570&hash=d41d8cd98f00b204e9800998ecf8427e
2021-02-15 18:26:10.318 &wind_avg=6.8&wind_max=5.51&wind_dir=191 
Should something like this:

Code: Select all

 2021-02-15 18:26:10.318 Status: dzVents: Debug: md5Hash: OpenURL: url = http://www.windguru.cz/upload/api.php?uid=IDstation&salt=1613413570&hash=d41d8cd98f00b204e9800998ecf8427e&wind_avg=6.8&wind_max=5.51&wind_dir=191 
I have tried fix the issue without success
Toulon7559 wrote: Monday 15 February 2021 17:05 Do you need online Hash-coding, or only a onetime Hash-coding for your password?
In the latter case plenty of tools available at internet, such as https://www.md5hashgenerator.com/

Small advantage that you keep your 'open' secret key outside your script.
:( On the other hand, using a public internet-tool for crypting is not really safe either.
Thanks for the tip, the hash must be calculated every minute or every update value with my user, pass and time span, I have a node red flow working very well for a year, but I would prefer migrate to dzvents. Don´t care to much about security, this is just a wind satiton, not my bank or email account. ;)

Re: MD5 hash algorithm?

Posted: Monday 15 February 2021 20:05
by waaren
javalin wrote: Monday 15 February 2021 19:30 works, but the 'hash function' finish creating a new line after show the hash.
Can you try again after changing line

Code: Select all

     dz.log("md5Hash of " ..mySecret .. " is " .. osCommand('echo -n ' .. mySecret .. ' | md5sum |  cut -d " " -f1'), dz.LOG_FORCE )
 
to

Code: Select all

        dz.log("md5Hash of " ..mySecret .. " is " ..  osCommand('echo -n ' .. mySecret .. ' | md5sum'):match("(%w+)")  , dz.LOG_FORCE )

Re: MD5 hash algorithm?

Posted: Monday 15 February 2021 22:06
by javalin
Can you try again after changing line
Now is working waaren. Thank you. This is the code, I would like to share in first post after your review ;)

Code: Select all

--Device attributes: wind.speed, wind.gust, wind.direction, wind.directionString
return
{
    on =
    {
        devices =
        {
            295, --script is executed every change of state of the weather station, must be your wind station device number  
        },

    },

    logging =
    {
        level = domoticz.LOG_ERROR ,
    },

    execute = function(dz, item)
        local wind = dz.devices(295)      -- your wind station device number, wind station have to work with knots units
        local uid = 'your_id'                    -- your Windguru station id 
        local station_pass = 'your_pass'   -- your Windguru station password 
        local time_stamp = dz.time.dDate
        local wind_speed = dz.utils.round(wind.speed,2)
        local wind_gust = dz.utils.round(wind.gust,2)
        local wind_direction = math.floor(wind.direction)
        local wind_directionString = wind.directionString
        local mySecret = time_stamp..uid..station_pass
        
        local function osCommand(cmd)
            dz.log('Executing Command: ' .. cmd,dz.LOG_DEBUG)
            local fileHandle = assert(io.popen(cmd .. ' 2>&1 || echo ::ERROR::', 'r'))
            local commandOutput = assert(fileHandle:read('*a'))
            local returnTable = {fileHandle:close()}
            if commandOutput:find '::ERROR::' then     -- something went wrong
               dz.log('Error ==>> ' .. tostring(commandOutput:match('^(.*)%s+::ERROR::') or ' ... but no error message ' ) ,dz.LOG_ERROR)
            else -- all is fine!!
                dz.log('ReturnCode: ' .. returnTable[3] .. '\ncommandOutput:\n' .. commandOutput, dz.LOG_DEBUG)
            end
            return commandOutput,returnTable[3] -- rc[3] contains returnCode
        end
        dz.log("md5Hash of " ..mySecret .. " is " ..  osCommand('echo -n ' .. mySecret .. ' | md5sum'):match("(%w+)")  , dz.LOG_DEBUG )
        local hash = tostring(osCommand('echo -n ' .. mySecret .. ' | md5sum'):match("(%w+)"))

	    if (item.isDevice) then 
        dz.openURL({
                url = 'http://www.windguru.cz/upload/api.php?uid='..uid..'&salt='..time_stamp..'&hash='..hash..'&wind_avg='..wind_speed..'&wind_max='..wind_gust..'&wind_dir='..wind_direction,
                method = 'GET',
        })
        return
        end
end
}

Re: MD5 hash algorithm?

Posted: Monday 15 February 2021 22:40
by waaren
javalin wrote: Monday 15 February 2021 22:06 Now is working waaren. Thank you. This is the code, I would like to share in first post after your review ;)
Seems ok. I propose some small changes (see below) and maybe you could add a clarification on what the script is for and that it only works on linux type systems with an available md5sum executable

Code: Select all

--Device attributes: wind.speed, wind.gust, wind.direction, wind.directionString

return
{
    on =
    {
        devices =
        {
            295, --script is executed every change of state of the weather station, must be your wind station device number  
        },
    },

    logging =
    {
        level = domoticz.LOG_ERROR,
		marker = 'windGuru',
    },

    execute = function(dz, item)
        local wind = item                   -- your wind station device number, wind station have to work with knots units
        local uid = 'your_id'                    -- your Windguru station id 
        local station_pass = 'your_pass'   -- your Windguru station password 
        local time_stamp = dz.time.dDate
        local wind_speed = dz.utils.round(wind.speed,2)
        local wind_gust = dz.utils.round(wind.gust,2)
        local wind_direction = math.floor(wind.direction)
        local wind_directionString = wind.directionString
        local mySecret = time_stamp .. uid .. station_pass
        
        local function osCommand(cmd)
            dz.log('Executing Command: ' .. cmd,dz.LOG_DEBUG)
            local fileHandle = assert(io.popen(cmd .. ' 2>&1 || echo ::ERROR::', 'r'))
            local commandOutput = assert(fileHandle:read('*a'))
            local returnTable = {fileHandle:close()}
            if commandOutput:find '::ERROR::' then     -- something went wrong
               dz.log('Error ==>> ' .. tostring(commandOutput:match('^(.*)%s+::ERROR::') or ' ... but no error message ' ) ,dz.LOG_ERROR)
            else -- all is fine!!
                dz.log('ReturnCode: ' .. returnTable[3] .. '\ncommandOutput:\n' .. commandOutput, dz.LOG_DEBUG)
            end
            return commandOutput,returnTable[3] -- rc[3] contains returnCode
        end

	local hash = osCommand('echo -n ' .. mySecret .. ' | md5sum'):match("(%w+)")
        dz.log("md5Hash of " ..mySecret .. " is " ..  hash , dz.LOG_DEBUG )
		dz.openURL( 'http://www.windguru.cz/upload/api.php?uid='..uid..'&salt='..time_stamp..'&hash=' ..
					hash..'&wind_avg='..wind_speed..'&wind_max='..wind_gust..'&wind_dir='..wind_direction)
	end
}