Re: dtgbot - Domoticz TeleGram BOT
Posted: Friday 12 May 2017 10:00
Hmmm just removed the device (kodi) and dtgbot seems to have come alive, weird.
Open source Home Automation System
https://forum.domoticz.com/
Code: Select all
-- A set of support functions currently aimed at dtgbot,
-- but probably more general
function form_device_name(parsed_cli)
-- joins together parameters after the command name to form the full "device name"
command = parsed_cli[2]
DeviceName = parsed_cli[3]
len_parsed_cli = #parsed_cli
if len_parsed_cli > 3 then
for i = 4, len_parsed_cli do
DeviceName = DeviceName..' '..parsed_cli[i]
end
end
return DeviceName
end
-- returns list of all user variables - called early by dtgbot
-- in case Domoticz is not running will retry
-- allowing Domoticz time to start
function variable_list()
local t, jresponse, status, decoded_response
t = server_url.."/json.htm?type=command¶m=getuservariables"
jresponse = nil
domoticz_tries = 1
-- Domoticz seems to take a while to respond to getuservariables after start-up
-- So just keep trying after 1 second sleep
while (jresponse == nil) do
print_to_log(1,"JSON request <"..t..">");
jresponse, status = http.request(t)
if (jresponse == nil) then
socket.sleep(1)
domoticz_tries = domoticz_tries + 1
if domoticz_tries > 100 then
print_to_log(0,'Domoticz not sending back user variable list')
break
end
end
end
print_to_log(0,'Domoticz returned getuservariables after '..domoticz_tries..' attempts')
decoded_response = JSON:decode(jresponse)
return decoded_response
end
-- returns idx of a user variable from name
function variable_list_names_idxs()
local idx, k, record, decoded_response
decoded_response = variable_list()
result = decoded_response["result"]
variables = {}
for i = 1, #result do
record = result[i]
if type(record) == "table" then
variables[record['Name']] = record['idx']
end
end
return variables
end
function idx_from_variable_name(DeviceName)
return Variablelist[DeviceName]
end
-- returns the value of the variable from the idx
function get_variable_value(idx)
local t, jresponse, decoded_response
if idx == nill then
return ""
end
t = server_url.."/json.htm?type=command¶m=getuservariable&idx="..tostring(idx)
print_to_log(1,"JSON request <"..t..">");
jresponse, status = http.request(t)
decoded_response = JSON:decode(jresponse)
print_to_log(0,'Decoded '..decoded_response["result"][1]["Value"])
return decoded_response["result"][1]["Value"]
end
function set_variable_value(idx,name,type,value)
-- store the value of a user variable
local t, jresponse, decoded_response
t = server_url.."/json.htm?type=command¶m=updateuservariable&idx="..idx.."&vname="..name.."&vtype="..type.."&vvalue="..tostring(value)
print_to_log(1,"JSON request <"..t..">");
jresponse, status = http.request(t)
return
end
function create_variable(name,type,value)
-- creates user variable
local t, jresponse, decoded_response
t = server_url.."/json.htm?type=command¶m=saveuservariable&vname="..name.."&vtype="..type.."&vvalue="..tostring(value)
print_to_log(1,"JSON request <"..t..">");
jresponse, status = http.request(t)
return
end
-- returns a device table of Domoticz items based on type i.e. devices or scenes
function device_list(DeviceType)
local t, jresponse, status, decoded_response
t = server_url.."/json.htm?type="..DeviceType.."&order=name&used=true"
print_to_log(1,"JSON request <"..t..">");
jresponse, status = http.request(t)
decoded_response = JSON:decode(jresponse)
return decoded_response
end
-- returns a list of Domoticz items based on type i.e. devices or scenes
function device_list_names_idxs(DeviceType)
--returns a devcie idx based on its name
local idx, k, record, decoded_response
decoded_response = device_list(DeviceType)
result = decoded_response['result']
devices = {}
devicesproperties = {}
for i = 1, #result do
record = result[i]
if type(record) == "table" then
if DeviceType == "plans" then
devices[record['Name']] = record['idx']
else
devices[string.lower(record['Name'])] = record['idx']
devices[record['idx']] = record['Name']
if DeviceType == 'scenes' then
devicesproperties[record['idx']] = {Type=record['Type'], SwitchType = record['Type']}
end
end
end
end
return devices, devicesproperties
end
function idx_from_name(DeviceName,DeviceType)
--returns a devcie idx based on its name
if DeviceType == "devices" then
return Devicelist[string.lower(DeviceName)]
elseif DeviceType == "scenes" then
return Scenelist[string.lower(DeviceName)]
else
return Roomlist[DeviceName]
end
end
function retrieve_status(idx,DeviceType)
local t, jresponse, status, decoded_response
t = server_url.."/json.htm?type="..DeviceType.."&rid="..tostring(idx)
print_to_log(1,"JSON request <"..t..">");
jresponse, status = http.request(t)
decoded_response = JSON:decode(jresponse)
return decoded_response
end
-- support function to scan through the Devices and Scenes idx tables and retrieve the required information for it
function devinfo_from_name(idx,DeviceName,DeviceScene)
local k, record, Type,DeviceType,SwitchType
local found = 0
local rDeviceName=""
local status=""
local MaxDimLevel=100
local ridx=0
local tvar
if DeviceScene~="scenes" then
-- Check for Devices
-- Have the device name
if DeviceName ~= "" then
idx = idx_from_name(DeviceName,'devices')
end
print_to_log(2,"==> start devinfo_from_name", idx,DeviceName)
if idx ~= nil then
test = retrieve_status(idx,"devices")['result']
if test ~= nil then
record = test[1]
--~ record = retrieve_status(idx,"devices")['result'][1]
print_to_log(2,'device ',DeviceName,record.Name,idx,record.idx)
if type(record) == "table" then
ridx = record.idx
rDeviceName = record.Name
DeviceType="devices"
Type=record.Type
-- as default simply use the status field
-- use the dtgbot_type_status to retrieve the status from the "other devices" field as defined in the table.
if dtgbot_type_status[Type] ~= nil then
if dtgbot_type_status[Type].Status ~= nil then
status = ''
CurrentStatus = dtgbot_type_status[Type].Status
for i=1, #CurrentStatus do
if status ~= '' then
status = status .. ' - '
end
cindex, csuffix = next(CurrentStatus[i])
status = status .. tostring(record[cindex])..tostring(csuffix)
end
end
else
SwitchType=record.SwitchType
MaxDimLevel=record.MaxDimLevel
status = tostring(record.Status)
end
found = 1
print_to_log(2," !!!! found device",record.Name,rDeviceName,record.idx,ridx)
end
end
end
print_to_log(2," !!!! found device",rDeviceName,ridx)
end
-- Check for Scenes
if DeviceScene=="scenes" then
if found == 0 then
if DeviceName ~= "" then
idx = idx_from_name(DeviceName,'scenes')
else
DeviceName = idx_from_name(idx,'scenes')
end
if idx ~= nil then
DeviceName = Scenelist[idx]
DeviceType="scenes"
ridx = idx
rDeviceName = DeviceName
SwitchType = Sceneproperties[tostring(idx)]['SwitchType']
Type = Sceneproperties[tostring(idx)]['Type']
found = 1
end
end
end
-- Check for Scenes
if found == 0 then
ridx = 9999
DeviceType="command"
Type="command"
SwitchType="command"
end
print_to_log(2," --< devinfo_from_name:",found,ridx,rDeviceName,DeviceType,Type,SwitchType,status)
return ridx,rDeviceName,DeviceType,Type,SwitchType,MaxDimLevel,status
end
function file_exists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
end
function domoticz_language()
local t, jresponse, status, decoded_response
t = server_url.."/json.htm?type=command¶m=getlanguage"
jresponse = nil
print_to_log(1,"JSON request <"..t..">");
jresponse, status = http.request(t)
decoded_response = JSON:decode(jresponse)
local language = decoded_response['language']
if language ~= nil then
return language
else
return 'en'
end
end
My Ubuntu server is 64 bit.maomanna wrote:but do you have a x86 or x64 ubuntu server?G3rard wrote:I have dtgbot working on my Ubuntu server. It took some extra steps which I think I have written down. Will have a look at it this weekend and share the steps here.
I'm running the latest beta 3.7450, but i think i figured it out. Because the hardware i removed (kodi) can't be found in the hardware list any more (now called kodi players). So i figure it has to do with that and not with the script. Maybe this is the solution for maomanna and his raspberry pi, remove the device that doesn't give any results and add the new "updated" hardware.jvdz wrote:Strange.. You have exactly the same issue! That JSON should contain a RESULT section with more information.
What is that device exactly and which version of Domoticz are you running?
I have a test version of dtg_domoticz.lua you could test to see if that ignores these type of device responses, but it clearly is a wrong response for a regular device.
Jos
test version code of dtg_domoticz.lua:Code: Select all
-- A set of support functions currently aimed at dtgbot, -- but probably more general function form_device_name(parsed_cli) -- joins together parameters after the command name to form the full "device name" command = parsed_cli[2] DeviceName = parsed_cli[3] len_parsed_cli = #parsed_cli if len_parsed_cli > 3 then for i = 4, len_parsed_cli do DeviceName = DeviceName..' '..parsed_cli[i] end end return DeviceName end -- returns list of all user variables - called early by dtgbot -- in case Domoticz is not running will retry -- allowing Domoticz time to start function variable_list() local t, jresponse, status, decoded_response t = server_url.."/json.htm?type=command¶m=getuservariables" jresponse = nil domoticz_tries = 1 -- Domoticz seems to take a while to respond to getuservariables after start-up -- So just keep trying after 1 second sleep while (jresponse == nil) do print_to_log(1,"JSON request <"..t..">"); jresponse, status = http.request(t) if (jresponse == nil) then socket.sleep(1) domoticz_tries = domoticz_tries + 1 if domoticz_tries > 100 then print_to_log(0,'Domoticz not sending back user variable list') break end end end print_to_log(0,'Domoticz returned getuservariables after '..domoticz_tries..' attempts') decoded_response = JSON:decode(jresponse) return decoded_response end -- returns idx of a user variable from name function variable_list_names_idxs() local idx, k, record, decoded_response decoded_response = variable_list() result = decoded_response["result"] variables = {} for i = 1, #result do record = result[i] if type(record) == "table" then variables[record['Name']] = record['idx'] end end return variables end function idx_from_variable_name(DeviceName) return Variablelist[DeviceName] end -- returns the value of the variable from the idx function get_variable_value(idx) local t, jresponse, decoded_response if idx == nill then return "" end t = server_url.."/json.htm?type=command¶m=getuservariable&idx="..tostring(idx) print_to_log(1,"JSON request <"..t..">"); jresponse, status = http.request(t) decoded_response = JSON:decode(jresponse) print_to_log(0,'Decoded '..decoded_response["result"][1]["Value"]) return decoded_response["result"][1]["Value"] end function set_variable_value(idx,name,type,value) -- store the value of a user variable local t, jresponse, decoded_response t = server_url.."/json.htm?type=command¶m=updateuservariable&idx="..idx.."&vname="..name.."&vtype="..type.."&vvalue="..tostring(value) print_to_log(1,"JSON request <"..t..">"); jresponse, status = http.request(t) return end function create_variable(name,type,value) -- creates user variable local t, jresponse, decoded_response t = server_url.."/json.htm?type=command¶m=saveuservariable&vname="..name.."&vtype="..type.."&vvalue="..tostring(value) print_to_log(1,"JSON request <"..t..">"); jresponse, status = http.request(t) return end -- returns a device table of Domoticz items based on type i.e. devices or scenes function device_list(DeviceType) local t, jresponse, status, decoded_response t = server_url.."/json.htm?type="..DeviceType.."&order=name&used=true" print_to_log(1,"JSON request <"..t..">"); jresponse, status = http.request(t) decoded_response = JSON:decode(jresponse) return decoded_response end -- returns a list of Domoticz items based on type i.e. devices or scenes function device_list_names_idxs(DeviceType) --returns a devcie idx based on its name local idx, k, record, decoded_response decoded_response = device_list(DeviceType) result = decoded_response['result'] devices = {} devicesproperties = {} for i = 1, #result do record = result[i] if type(record) == "table" then if DeviceType == "plans" then devices[record['Name']] = record['idx'] else devices[string.lower(record['Name'])] = record['idx'] devices[record['idx']] = record['Name'] if DeviceType == 'scenes' then devicesproperties[record['idx']] = {Type=record['Type'], SwitchType = record['Type']} end end end end return devices, devicesproperties end function idx_from_name(DeviceName,DeviceType) --returns a devcie idx based on its name if DeviceType == "devices" then return Devicelist[string.lower(DeviceName)] elseif DeviceType == "scenes" then return Scenelist[string.lower(DeviceName)] else return Roomlist[DeviceName] end end function retrieve_status(idx,DeviceType) local t, jresponse, status, decoded_response t = server_url.."/json.htm?type="..DeviceType.."&rid="..tostring(idx) print_to_log(1,"JSON request <"..t..">"); jresponse, status = http.request(t) decoded_response = JSON:decode(jresponse) return decoded_response end -- support function to scan through the Devices and Scenes idx tables and retrieve the required information for it function devinfo_from_name(idx,DeviceName,DeviceScene) local k, record, Type,DeviceType,SwitchType local found = 0 local rDeviceName="" local status="" local MaxDimLevel=100 local ridx=0 local tvar if DeviceScene~="scenes" then -- Check for Devices -- Have the device name if DeviceName ~= "" then idx = idx_from_name(DeviceName,'devices') end print_to_log(2,"==> start devinfo_from_name", idx,DeviceName) if idx ~= nil then test = retrieve_status(idx,"devices")['result'] if test ~= nil then record = test[1] --~ record = retrieve_status(idx,"devices")['result'][1] print_to_log(2,'device ',DeviceName,record.Name,idx,record.idx) if type(record) == "table" then ridx = record.idx rDeviceName = record.Name DeviceType="devices" Type=record.Type -- as default simply use the status field -- use the dtgbot_type_status to retrieve the status from the "other devices" field as defined in the table. if dtgbot_type_status[Type] ~= nil then if dtgbot_type_status[Type].Status ~= nil then status = '' CurrentStatus = dtgbot_type_status[Type].Status for i=1, #CurrentStatus do if status ~= '' then status = status .. ' - ' end cindex, csuffix = next(CurrentStatus[i]) status = status .. tostring(record[cindex])..tostring(csuffix) end end else SwitchType=record.SwitchType MaxDimLevel=record.MaxDimLevel status = tostring(record.Status) end found = 1 print_to_log(2," !!!! found device",record.Name,rDeviceName,record.idx,ridx) end end end print_to_log(2," !!!! found device",rDeviceName,ridx) end -- Check for Scenes if DeviceScene=="scenes" then if found == 0 then if DeviceName ~= "" then idx = idx_from_name(DeviceName,'scenes') else DeviceName = idx_from_name(idx,'scenes') end if idx ~= nil then DeviceName = Scenelist[idx] DeviceType="scenes" ridx = idx rDeviceName = DeviceName SwitchType = Sceneproperties[tostring(idx)]['SwitchType'] Type = Sceneproperties[tostring(idx)]['Type'] found = 1 end end end -- Check for Scenes if found == 0 then ridx = 9999 DeviceType="command" Type="command" SwitchType="command" end print_to_log(2," --< devinfo_from_name:",found,ridx,rDeviceName,DeviceType,Type,SwitchType,status) return ridx,rDeviceName,DeviceType,Type,SwitchType,MaxDimLevel,status end function file_exists(name) local f=io.open(name,"r") if f~=nil then io.close(f) return true else return false end end function domoticz_language() local t, jresponse, status, decoded_response t = server_url.."/json.htm?type=command¶m=getlanguage" jresponse = nil print_to_log(1,"JSON request <"..t..">"); jresponse, status = http.request(t) decoded_response = JSON:decode(jresponse) local language = decoded_response['language'] if language ~= nil then return language else return 'en' end end
I did the following steps to make dtgbot working on my Ubuntu server 14.04 x64.maomanna wrote:How did you compile the lua libraries?
In the OP is a 32bit version supplied.
Code: Select all
/usr/bin/lua5.2: /usr/local/share/lua/5.2/JSON.lua:383: nil passed to JSON:decode()
stack traceback:
[C]: in function 'assert'
/usr/local/share/lua/5.2/JSON.lua:383: in function 'onDecodeOfNilError'
/usr/local/share/lua/5.2/JSON.lua:644: in function 'decode'
/home/pi/dtgbot//dtg_domoticz.lua:40: in function 'variable_list'
/home/pi/dtgbot//dtg_domoticz.lua:47: in function 'variable_list_names_idxs'
/home/pi/dtgbot/dtgbot.lua:184: in function 'dtgbot_initialise'
/home/pi/dtgbot/dtgbot.lua:229: in main chunk
[C]: in ?
Code: Select all
2017-05-22 15:51:59 - DomoticzIP: USER:[email protected]
2017-05-22 15:51:59 - DomoticzPort: 8010
2017-05-22 15:51:59 - BotHomePath: /home/pi/dtgbot/
2017-05-22 15:51:59 - BotLuaScriptPath: /home/pi/dtgbot/lua/
2017-05-22 15:51:59 - TempFileDir: /home/pi/domoticz/scripts/temp/
2017-05-22 15:51:59 - BotBashScriptPath: /home/pi/dtgbot/bash/
2017-05-22 15:51:59 - TelegramBotToken: BOT:Token
2017-05-22 15:51:59 - TelegramBotOffset: TelegramBotOffset
2017-05-22 15:51:59 - -----------------------------------------
2017-05-22 15:51:59 - Starting Telegram api Bot message handler
2017-05-22 15:51:59 - -----------------------------------------
2017-05-22 15:51:59 - Using DTGBOT config file:/home/pi/dtgbot//dtgbot.cfg
2017-05-22 15:53:39 - Domoticz not sending back user variable list
2017-05-22 15:53:39 - Domoticz returned getuservariables after 101 attempts
Did you manage to find a solution for this? I'm also thinking of implementing a couple of yes/no questions on certain times.DennisD wrote:Good thinking, i have to come up with something!
Code: Select all
voice: {
duration: 1,
mime_type: "audio/ogg",
file_id: "AwADBAADWgEAAhtjXXXXKFGC7DJusDAI",
file_size: 4067
}
Code: Select all
text: "Test"
Code: Select all
https://api.telegram.org/bot<bot_token>/getFile?file_id=the_file_id
Code: Select all
{
ok: true,
result: {
file_id: "AwADBAADWgEAAhtjXXXXFGC7DJusDAI",
file_size: 4067,
file_path: "voice/111111088413725018.oga"
}
}
Code: Select all
https://api.telegram.org/file/bot<token>/<file_path>
Code: Select all
voice url-for-filedownload
Great, looking forward to this!jvdz wrote: ↑Thursday 10 August 2017 9:32 I will wip something up probably this evening to support voice files. What I am considering is to have it perform the following command when a voice file is received:So you would need to have a voice.sh or lua that will download the file with curl and then process it.Code: Select all
voice url-for-filedownload
As to your question: How do you process the Announcement commands? Need to check but though all parameters are copied to the shelled process.
Jos
Code: Select all
Announcement This is a test announcement
Code: Select all
Announcement This-is-a-test-announcement
or
Announcement This_is_a_test_announcement