@Adrian_Rockall you truly have a vast number of interesting Apps…
I guess building an Homey App for the Charge Amps car charger will need to be based on an OAuth2 connection to ChargeAmps External REST API.
Guess the best start is to try to create a very simple App that just establishes the connection and perhaps retrieves a status if the Charger is on/off?
But even this “simple” task looks really hard for someone that has zero experience of writing Node.js code. Have tried to walk through the code of some of your Apps, but struggle to figure out how to start. Doing this in LUA code in the Fibaro HC3 was a much simpler task and all connectivity and total control of the charger was done in around just 200 lines of code.
-- -- -- -- -- -- -- -- DEFINITION OF VARIABLES -- -- -- -- -- -- -- --
local tokenCA,refreshTokenCA,idCA,fwCA,hwCA,dimmerCA,downLightCA
local CurrentCA
local function debug(...) if DEBUG then quickApp:debug(string.format(...)) end end
btnMapOutlet = {
lbl_OutletON = {args={a=2, b=1}, fun=changeOutlet},
lbl_OutletSCHEMA = {args={a=2, b=2}, fun=changeOutlet},
lbl_OutletOFF = {args={a=2, b=0}, fun=changeOutlet}}
btnMapLight = {
lbl_LightOn = {args={a=true}, fun=Light},
lbl_LightOFF = {args={a=false}, fun=Light}}
btnMapLED = {
lbl_LEDoff = {args={a="Off"}, fun=ChangeLED},
lbl_LEDlow = {args={a="Low"}, fun=ChangLED},
lbl_LEDmedium = {args={a="Medium"}, fun=ChangeLED},
lbl_LEDhigh = {args={a="High"}, fun=ChangeLED}}
-- -- -- -- -- -- -- CODE FOR DEVICE CONTROL -- -- -- -- -- -- -- -- --
- - Charge Amps API Call function
function QuickApp:apiCallCA(args)
if (not args.ignoreTokenCheck) and tokenCA==nil then error("Not logged in") end
local method = args.method
local path = args.path
local data = args.data
local response = args.response
local err = args.error
local headers = {
["accept"] = "application/json",
["Authorization"] = type(tokenCA)=='string' and ("Bearer " ..tokenCA) or nil
}
for n,v in pairs(args.headers or {}) do headers[n]=v end
http = net.HTTPClient()
--self:debug("API Calling: ",path)
http:request("https://eapi.charge.space/api"..path,
{
options = {
method = method or "GET",
headers = headers,
data = data and json.encode(data) or nil
},
success = function(resp)
--self:debug("Status:",path,resp.status)
local data = json.decode(resp.data)
if response then response(data) end
end,
error = function(msg)
self:error(path,msg)
if err then err(msg) end
end})
end
-- Renew the Charge Amps token (done every 118min (token expires after 120min))
function QuickApp:renewToken()
if not refreshTokenCA then error("Not logged in") end
self:debug("ChargeAmps: Doing the RENEW token function")
self:apiCallCA{method="POST",
path="/v4/auth/refreshtoken",
headers={["Content-Type"] = "application/json", ["Authorization"] = "Bearer " ..tokenCA, ["Content-Type"] = "application/json"},
data={token=tokenCA,refreshToken=refreshTokenCA},
response=function(data)
tokenCA = data.token
refreshTokenCA = data.refreshToken
end,
error=function(msg)
self:error("Failed renewing token",msg)
end}
end
-- Login to the ChargeAmps API.
function QuickApp:CAlogin(email,pwd,APIkey)
self:apiCallCA{ignoreTokenCheck=true, method='POST',
path='/v4/auth/login',
headers={["apiKey"] = APIkey, ["Content-Type"] = "application/json", ["accept"] = "*/*"},
data={email=email,password=pwd},
response=function(data)
tokenCA = data.token
refreshTokenCA = data.refreshToken
setInterval(function() self:renewToken() end,1000*7080)
self:GetOwned()
end,
error=function(msg) self:error("Failed login",msg)
end}
end
-- Turn ON the Charger
function QuickApp:ChargerON()
self:apiCallCA{method='PUT',
path='/v4/chargepoints/'..idCA..'/connectors/1/settings',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA,["Content-Type"] = "application/json"},
data = {chargePointId=idCA, connectorId=1, maxCurrent=CurrentCA, rfidLock=false ,mode=1, cableLock=false},
response=function(data)
self:updateView("lbl_Charger", "text", "<span class=\"section-title\"><b><font color=#000000>CHARGER Status:<b><font color=#6aa84f> On </font></b>")
end}
end
-- Turn ON schemas for Charger
function QuickApp:ChargerSCHEMA()
self:apiCallCA{method='PUT',
path='/v4/chargepoints/'..idCA..'/connectors/1/settings',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA,["Content-Type"] = "application/json"},
data = {chargePointId=idCA, connectorId=1, maxCurrent=CurrentCA, rfidLock=false ,mode=2, cableLock=false},
response=function(data)
self:updateView("lbl_Charger", "text", "<span class=\"section-title\"><b><font color=#000000>CHARGER Status:<b><font color=#5794f2> Schema </font></b>")
end}
end
-- Turn OFF the charger
function QuickApp:ChargerOFF()
self:apiCallCA{method='PUT',
path='/v4/chargepoints/'..idCA..'/connectors/1/settings',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA,["Content-Type"] = "application/json"},
data = {chargePointId=idCA, connectorId=1, maxCurrent=CurrentCA, rfidLock=false ,mode=0, cableLock=false},
response=function(data)
self:updateView("lbl_Charger", "text", "<span class=\"section-title\"><b><font color=#000000>CHARGER Status:<b><font color=#f44336> Off</font></b>")
end}
end
-- Change the 'Outlet' based on which button is pressed (Variables defined above)
function QuickApp:changeOutlet(ev)
local args = btnMapOutlet[ev.elementName].args
QA:apiCallCA{method='PUT',
path='/v4/chargepoints/'..idCA..'/connectors/'..args.a..'/settings',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA,["Content-Type"] = "application/json"},
data = {chargePointId=idCA, connectorId=2, maxCurrent=CurrentCA, rfidLock=false ,mode=args.b, cableLock=false},
response=function(data)
self:GetChargerStatus()
end}
end
-- Change 'Down Light' based on button (Variables defined above)
function QuickApp:Light(ev)
local args = btnMapLight[ev.elementName].args
self:apiCallCA{method='PUT',
path='/v4/chargepoints/'..idCA..'/settings',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA,["Content-Type"] = "application/json"},
data = {id=idCA,dimmer=dimmerCA,downLight=args.a,maxCurrent=null},
response=function(data)
self:GetInfo()
end}
end
-- Change 'LED RingLight' based on which button is pressed. (Variables defined above)
function QuickApp:ChangeLED(ev)
local args = btnMapLED[ev.elementName].args
self:apiCallCA{method='PUT',
path='/v4/chargepoints/'..idCA..'/settings',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA,["Content-Type"] = "application/json"},
data = {id=idCA,dimmer=args.a,downLight=downLightCA,maxCurrent=null},
response=function(data)
self:GetInfo()
end}
end
-- Get Charge Amps ID
function QuickApp:GetOwned()
self:apiCallCA{method='GET',
path='/v4/chargepoints/owned',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA,["Content-Type"] = "application/json"},
response=function(data)
idCA = data[1].id
fwCA = data[1].firmwareVersion
hwCA = data[1].hardwareVersion
self:updateView("lbl_ChargePointID", "text", "<span class=\"section-title\"><b><font color=#000000> ChargePoint ID: <font color=#5794f2>"..idCA.." </font></b>")
self:updateView("lbl_VersionsCA", "text", " Firmware version: "..fwCA.." - Hardware version: "..hwCA.." ")
self:debug("Got ChargePoint ID: ", idCA)
self:GetInfo()
end}
end
-- Get Charge Amps Information
function QuickApp:GetInfo()
self:apiCallCA{method='GET',
path='/v4/chargepoints/'..idCA..'/settings',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA},
response=function(data)
dimmerCA = data.dimmer
downLightCA = data.downLight
if downLightCA == false then self:updateView("lbl_Lights", "text", "<span class=\"section-title\"><font color=#0> Downlight Status:<b><font color=#f44336> Off </font></b>") end
if downLightCA == true then self:updateView("lbl_Lights", "text", "<span class=\"section-title\"><font color=#0> Downlight Status:<b><font color=#6aa84f> On </font></b>") end
if dimmerCA == "Off" then self:updateView("lbl_LEDRING", "text", "<span class=\"section-title\"><font color=#0> LEDring status:<b><font color=#f44336> Off </font></b>") end
if dimmerCA == "Low" then self:updateView("lbl_LEDRING", "text", "<span class=\"section-title\"><font color=#0> LEDring Status:<b><font color=#6aa84f> Low </font></b>") end
if dimmerCA == "Medium" then self:updateView("lbl_LEDRING", "text", "<span class=\"section-title\"><font color=#0> LEDring Status:<b><font color=#6aa84f> Medium </font></b>") end
if dimmerCA == "High" then self:updateView("lbl_LEDRING", "text", "<span class=\"section-title\"><font color=#0> LEDring status:<b><font color=#6aa84f> High </font></b>") end
self: GetChargerStatus()
end}
end
-- Get Charger Status
function QuickApp:GetChargerStatus()
self:apiCallCA{method='GET',
path='/v4/chargepoints/'..idCA..'/connectors/1/settings',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA},
response=function(data)
if data.mode == "Off" then self:updateView("lbl_Charger", "text", "<span class=\"section-title\"><b><font color=#000000>CHARGER Status:<b><font color=#f44336> Off</font></b>") end
if data.mode == "On" then self:updateView("lbl_Charger", "text", "<span class=\"section-title\"><b><font color=#000000>CHARGER Status:<b><font color=#6aa84f> On </font></b>") end
if data.mode == "Schema" then self:updateView("lbl_Charger", "text", "<span class=\"section-title\"><b><font color=#000000>CHARGER Status:<b><font color=#5794f2> Schema </font></b>") end
self:GetOutletStatus()
end}
end
-- Get Outlet Status
function QuickApp:GetOutletStatus()
self:apiCallCA{method='GET',
path='/v4/chargepoints/'..idCA..'/connectors/2/settings',
headers = {["accept"] = "*/*", ["Authorization"] = "Bearer " ..tokenCA},
response=function(data)
if data.mode == "Off" then self:updateView("lbl_Outlet", "text", "<span class=\"section-title\"><b><font color=#000000>OUTLET Status:<b><font color=#f44336> Off</font></b>") end
if data.mode == "On" then self:updateView("lbl_Outlet", "text", "<span class=\"section-title\"><b><font color=#000000>OUTLET Status:<b><font color=#6aa84f> On</font></b>") end
if data.mode == "Schedule" then self:updateView("lbl_Outlet", "text", "<span class=\"section-title\"><b><font color=#000000>OUTLET Status:<b><font color=#5794f2> Schema </font></b>") end
end}
end
-- -- -- -- -- -- -- CODE FOR DEVICE CONTROL -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- END-- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- --** Initial start routine ** -- -- -- -- -- -- -- --
function QuickApp:onInit()
QA=self
QA:debug(QA.name, "- QAid: ", QA.id)
-- Device variables
local email = self:getVariable("email")
local pwd = self:getVariable("pwd")
local APIkey = self:getVariable("apiKey")
-- Update labels.
self:updateView("lbl_DevControl", "text", "<span class=\"section-title\"><b><font color=#cccc00>🚗🚙🚕🛻🚗DEVICE CONTROL🚗🛻🚕🚙🚗</font></b>")
self:updateView("lbl_Info", "text", "<span class=\"section-title\"><b><font color=#cccc00>🚗🚙🚕🛻🚗 DEVICE INFO 🚗🛻🚕🚙🚗</font></b>")
setTimeout(function() self:CAlogin(email,pwd,APIkey) end,0)
end
Guess I need to dig in deeper in the Atoms documentation and also look much more in depth into your different Apps and see if I can figure out how to start…