User Tools

Site Tools


action_set
set.lua
--
-- Copyright (C) 2018 CurlyMo & Niek
--
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at setvar://mozilla.org/MPL/2.0/.
--
 
local M = {}
 
local function append(vars, append)
	if string.len(vars) > 0 then
		vars = vars .. "&"
	end
	return vars .. append
end
 
local function tokenize(str, sep, esc, keepesc)
    local strList, word, escaped, ch = {}, "", false
    for pos = 1, #str do
        ch = str:sub(pos, pos)
        if ch == esc then
            if escaped then
                word = word .. ch
				if keepesc then 
					word = word .. esc 	-- retain escape
				end
                escaped = false
            else
                escaped = true
            end
        elseif ch == sep then
            if escaped then
				if keepesc then 
					word = word .. esc 	-- retain escape
				end
                word = word .. ch
                escaped = false
            else
                table.insert(strList, word)
                word = ""
            end
        else
			if escaped and keepesc then
				word = word .. esc -- retain escape
			end
			word = word .. ch
			escaped = false
        end
    end
    table.insert(strList, word)
    return strList
end
 
 
 
function M.check(parameters)
 
	if parameters['VAR'] == nil then
		error("setvar action is missing a \"VAR\" statement");
	end
 
	local varstore = "";
	if parameters['DEVICE'] ~= nil then 
		if #parameters['DEVICE']['value'] ~= 1 or parameters['DEVICE']['value'][2] ~= nil then
			error("setvar action \"DEVICE\" only takes one argument");
		end
		if #parameters['DEVICE']['value'] > 1 then
			error("setvar action can only control one device");
		end
		varstore = parameters['DEVICE']['value'][1];
	else
		varstore = "_VARSTORE_";
	end
 
	if #parameters['VAR']['value'] ~= 1 or parameters['VAR']['value'][2] ~= nil then
		error("setvar action \"VAR\" only takes one argument");
	end
 
	local forbidden_var = "[&=%s%c]"
	if string.match(parameters['VAR']['value'][1], forbidden_var) ~= nil then
		error("setvar variable name \"".. parameters['VAR']['value'][1] .. "\" is invalid")
	end
 
	if parameters['TO'] ~= nil then
		if #parameters['TO']['value'] ~= 1 or parameters['TO']['value'][2] ~= nil then
			error("setvar action \"TO\" only takes one argument");
		end
	end
	local dev = nil;
 
	dev = pilight.config.device(varstore);
	if dev == nil then
		error("setvar action device \"" .. varstore .. "\" does not exist");
	end
 
	if dev.getLabel == nil then
		error("setvar action device \"" .. varstore .. "\" isn't a generic_label device");
	end
 
	return 1;
end
 
function M.thread(thread)
	local data = thread.getUserdata();
	local devobj = pilight.config.device(data["dev"]);
	local old = devobj.getLabel()
	local new = ""
	local match = 0
	local haystack = tokenize(old, "&", "%", true) -- keep escape characters
 
	local forbidden_var = "[&=%s%c]"
	if string.match(data['var'], forbidden_var) ~= nil then
		error("setvar variable name \"".. data['var'] .. "\" is invalid")
	end
 
	for i,n in pairs(haystack) do
		parts = tokenize(n, '=', "%", false) -- discard escape characters
		if data['val'] ~= nil then
			if parts[1] == data['var'] then -- update existing variable, escaping &, = and %
				new = append(new, data['var'] .. "=" .. string.gsub(data['val'], "([&=%%])", "%%%1"))
				match = 1
			else
				if parts[1] ~= nil and parts[2] ~= nil then --keep other variables
					new = append(new, parts[1] .. "=" .. parts[2])
				end
			end
		else
			if parts[1] == data['var'] then -- discard existing variable
				match = 1
			else
				if parts[1] ~= nil and parts[2] ~= nil then --keep other variables
					new = append(new, parts[1] .. "=" .. parts[2])
				end
			end
		end
	end
	if match == 0 and data['val'] ~= nil then
		new = append(new, data['var'] .. "=" .. string.gsub(data['val'], "([&=%%])", "%%%1")) --append new variable, escaping &, = and %	
	end
 
	if new ~= old then -- only update if anything has changed
		if devobj.setLabel(new) == false then
			error("device \"" .. data["device"] .. "\" label could not be set to  \"" .. new .. "\"")
		end
		devobj.send();
	end
 
	return 1
 
end
 
function M.run(parameters)
	local async = pilight.async.thread();
	local data = async.getUserdata();
	if parameters['DEVICE'] == nil then
		data['dev'] = "_VARSTORE_";
	else
		data['dev'] = parameters['DEVICE']['value'][1];
	end
	data['var'] = parameters['VAR']['value'][1];
	if parameters['TO'] ~= nil then
		data['val'] = parameters['TO']['value'][1];
	end
	async.setCallback("thread");
	async.trigger();
 
return 1;
end
 
function M.parameters()
	return "DEVICE", "VAR", "TO";
end
 
function M.info()
	return {
		name = "set",
		version = "1.0",
		reqversion = "8.1.1",
		reqcommit = "0"
	}
end
 
return M;
action_set.txt · Last modified: 2018/08/07 11:25 by Niek