En ce début d'année, j'ai fait l'acquisition d'une Renault Zoé ZE50. C'est une super voiture qui est surtout connectée.
Evidemment, j'ai trouvé là mon nouveau jouet à connecter à Domoticz.
- Activation/désactivation des plannings de charges
- Etat de la charge
- Etat du branchement
- Lancement du pré-conditionnement
- Lancement de la charge
- Localisation
- Kilométrage
- Autonomie renvoyée par l'api (MAJ seulement au débranchement ou fin de charge)
- Autonomie calculée
- Conso moyenne après la charge
- Suivi dépassement kilométrage location.
- Démarrage "Intelligent" de la charge
D'abord, le coeur de l'accès à l'api :
/home/pi/domoticz/scripts/python/MyRenault.py
Pour fonctionner, il a besoin d'un fichier contenant les identifiants :
/home/pi/domoticz/scripts/python/credentials.json
Code : Tout sélectionner
{
"RenaultServiceLocation": "fr_FR",
"RenaultServicesUsername": "adresse@gmail.com",
"RenaultServicesPassword": "MotDePasseMyRenault",
"VIN": "VF1NUMERODESERIE"
}
N'oubliez pas de créer les capteurs virtuels
/home/pi/domoticz/scripts/dzVents/scripts/zoe.lua
Code : Tout sélectionner
--Prérequis :
--Domoticz v2020.1 or later (dzVents version 3.0 or later)
-- sources : https://github.com/jamesremuscat/pyze
-- https://github.com/epenet/Renault-Zoe-API
local scriptName = 'Zoé'
local scriptVersion = '1.2'
-- 1.0 version initiale
-- 1.1 ajout custom events
-- 1.2 Authentification v2
-- Dummy à créer :
local batterieZoe = "Batterie Zoé" -- Pourcentage
local charge = "Charge Zoé" -- Interrupteur Custom avec les niveaux :
-- 0 Non Branchée
-- 10 Attente Charge Planifiée
-- 20 Charge Terminée
-- 30 Attente Charge Actuelle
-- 40 Trappe Ouverte
-- 50 En Charge
-- 60 Erreur De Charge
-- 70 Indisponible
local LancementCharge = "Lancer la Charge" -- Interrupteur Push On
local lanceAC = "Zoé Pré Chambrage" -- Interrupteur Push On
local plugStatus = "Zoé Branchée" -- Interrupteur
local chargeMode = "Charge Programmée" -- Interrupteur
local kilometrage = "Zoé" -- Compteur
local autonomie = "Autonomie Zoé" -- Custom
local autonomieReelleEstimee = "Autonomie Zoé Réelle" -- Custom
local consommationMoyenne = "Conso Zoé" -- Custom
local capaciteBatterie = 52 -- en kWh
--local tempBatt = "Temp Batterie Zoé" -- Température
local fichierTemp = "/var/tmp/zoe.txt" -- fichier de retour des requêtes
local credentials = "/home/pi/domoticz/scripts/python/credentials.json" -- Identifiants
local scriptPython = "/home/pi/domoticz/scripts/python/MyRenault.py"
local planningActive = "/home/pi/domoticz/scripts/python/chargeSchedule.json"
local planningDesactive = "/home/pi/domoticz/scripts/python/chargeScheduleFalse.json"
return {
active = true,
logging = {
level = domoticz.LOG_DEBUG, -- Uncomment to override the dzVents global logging setting
marker = scriptName..' '..scriptVersion
},
on = {
timer = {'every 2 minutes'},
devices = {
LancementCharge,
chargeMode,
lanceAC
},
customEvents =
{
'delayed',
},
},
data = {
notifZoe = {initial=false},
notifZoeKm = {initial=false},
kmFinDeCharge = {initial=345},
batterieFinDeCharge = {initial=100},
},
execute = function(domoticz, item)
local function readLuaFromJsonFile(fileName)
local file = io.open(fileName, 'r')
if file then
local contents = file:read('*a')
-- convertion en JSON respectant les normes
local lua_value = domoticz.utils.fromJSON(contents:gsub("\"",''):gsub("'",'"'):gsub("False","false"):gsub("True","true"):gsub("None",'"None"'))
io.close(file)
return lua_value
end
return nil
end
if (item.isCustomEvent) then
zoe = readLuaFromJsonFile(fichierTemp)
if(zoe)then
if (zoe.battery.data) then
domoticz.log("Autonomie fin de charge : "..zoe.battery.data.attributes.batteryAutonomy,domoticz.LOG_DEBUG)
domoticz.log("Batterie fin de charge : "..domoticz.data.batterieFinDeCharge,domoticz.LOG_DEBUG)
if (tonumber(zoe.battery.data.attributes.batteryAutonomy) ~= tonumber(domoticz.devices(autonomie).rawData[1])
or tonumber(zoe.battery.data.attributes.batteryAutonomy) ~= domoticz.data.kmFinDeCharge )then
domoticz.devices(autonomie).updateCustomSensor(zoe.battery.data.attributes.batteryAutonomy)
domoticz.devices(autonomieReelleEstimee).updateCustomSensor(zoe.battery.data.attributes.batteryAutonomy)
domoticz.data.kmFinDeCharge = zoe.battery.data.attributes.batteryAutonomy
domoticz.data.batterieFinDeCharge = zoe.battery.data.attributes.batteryLevel
domoticz.log("Batterie Fin de Charge : "..domoticz.data.batterieFinDeCharge,domoticz.LOG_DEBUG)
domoticz.log("Autonomie Fin de Charge : "..domoticz.data.kmFinDeCharge,domoticz.LOG_DEBUG)
consommation = math.floor(100*capaciteBatterie*domoticz.data.batterieFinDeCharge/domoticz.data.kmFinDeCharge)/100
domoticz.log( "Consommation : "..consommation, domoticz.LOG_INFO)
domoticz.devices(consommationMoyenne).updateCustomSensor(consommation)
end
domoticz.log("Batterie : "..zoe.battery.data.attributes.batteryLevel,domoticz.LOG_DEBUG)
if (zoe.battery.data.attributes.batteryLevel ~= domoticz.devices(batterieZoe).percentage
or domoticz.devices(batterieZoe).lastUpdate.minutesAgo >9)then
domoticz.devices(batterieZoe).updatePercentage(zoe.battery.data.attributes.batteryLevel)
if (zoe.battery.data.attributes.batteryLevel <= 40 and domoticz.data.notifZoe == false )then
domoticz.data.notifZoe = true
domoticz.log( "Batterie Zoé inférieure à 40 %.", domoticz.LOG_INFO)
domoticz.notify("Domobox","Il faudra recharger Zoé. Batterie Zoé inférieure à 40 %.",domoticz.PRIORITY_NORMAL)
end
kmAutonomieReelleEstimee = math.floor(domoticz.data.kmFinDeCharge / domoticz.data.batterieFinDeCharge * zoe.battery.data.attributes.batteryLevel)
domoticz.log( "Autonomie estimée : "..kmAutonomieReelleEstimee, domoticz.LOG_INFO)
domoticz.devices(autonomieReelleEstimee).updateCustomSensor(kmAutonomieReelleEstimee)
if (kmAutonomieReelleEstimee <= 40 and domoticz.data.notifZoeKm == false )then
domoticz.data.notifZoeKm = true
domoticz.log( "Autonomie Zoé inférieure à 40 Km.", domoticz.LOG_INFO)
domoticz.notify("Domobox","Il faudra recharger Zoé. Autonomie Zoé inférieure à 40 Km.",domoticz.PRIORITY_NORMAL)
end
end
-- Température non remontée par l'API pour l'instant pour la ZE50
-- domoticz.log("Temp Batterie : "..zoe.battery.data.attributes.batteryTemperature,domoticz.LOG_DEBUG)
-- if (tonumber(zoe.battery.data.attributes.batteryTemperature) ~= tonumber(domoticz.devices(tempBatt).temperature))then
-- domoticz.devices(tempBatt).updateTemperature(zoe.battery.data.attributes.batteryTemperature)
-- end
domoticz.log("Charge : "..zoe.battery.data.attributes.chargingStatus,domoticz.LOG_DEBUG)
if (tonumber(zoe.battery.data.attributes.chargingStatus) == 0 and domoticz.devices(charge).state ~= "Non Branchée")then
domoticz.devices(charge).switchSelector("Non Branchée")
elseif (tonumber(zoe.battery.data.attributes.chargingStatus) == 0.1 and domoticz.devices(charge).state ~= "Attente Charge Planifiée")then
domoticz.devices(charge).switchSelector("Attente Charge Planifiée")
elseif (tonumber(zoe.battery.data.attributes.chargingStatus) == 0.2 and domoticz.devices(charge).state ~= "Charge Terminée")then
domoticz.devices(charge).switchSelector("Charge Terminée")
elseif (tonumber(zoe.battery.data.attributes.chargingStatus) == 0.3 and domoticz.devices(charge).state ~= "Attente Charge Actuelle")then
domoticz.devices(charge).switchSelector("Attente Charge Actuelle")
elseif (tonumber(zoe.battery.data.attributes.chargingStatus) == 0.4 and domoticz.devices(charge).state ~= "Trappe Ouverte")then
domoticz.devices(charge).switchSelector("Trappe Ouverte")
elseif (tonumber(zoe.battery.data.attributes.chargingStatus) == 1 and domoticz.devices(charge).state ~= "En Charge")then
domoticz.devices(charge).switchSelector("En Charge")
domoticz.data.notifZoe = false
domoticz.data.notifZoeKm = false
elseif (tonumber(zoe.battery.data.attributes.chargingStatus) == -1 and domoticz.devices(charge).state ~= "Erreur De Charge")then
domoticz.devices(charge).switchSelector("Erreur De Charge")
elseif (tonumber(zoe.battery.data.attributes.chargingStatus) == -1.1 and domoticz.devices(charge).state ~= "Indisponible")then
domoticz.devices(charge).switchSelector("Indisponible")
end
domoticz.log("Plug Status : "..zoe.battery.data.attributes.plugStatus,domoticz.LOG_DEBUG)
if (tonumber(zoe.battery.data.attributes.plugStatus) == 0 )then
domoticz.devices(plugStatus).switchOff().checkFirst()
else
domoticz.devices(plugStatus).switchOn().checkFirst()
end
end
if (zoe.cockpit.data and zoe.chargemode.data and zoe.chargemode.data.attributes.schedules)then
domoticz.log("km : "..zoe.cockpit.data.attributes.totalMileage,domoticz.LOG_DEBUG)
if (tonumber(zoe.cockpit.data.attributes.totalMileage) ~= tonumber(domoticz.devices(kilometrage).counter))then
domoticz.devices(kilometrage).updateCounter(zoe.cockpit.data.attributes.totalMileage)
end
domoticz.log("mode planning : "..tostring(zoe.chargemode.data.attributes.schedules[1].activated),domoticz.LOG_DEBUG)
if (zoe.chargemode.data.attributes.schedules[1].activated and domoticz.devices(chargeMode).bState == false )then
domoticz.devices(chargeMode).switchOn().silent()
elseif (zoe.chargemode.data.attributes.schedules[1].activated == false and domoticz.devices(chargeMode).bState == true )then
domoticz.devices(chargeMode).switchOff().silent()
end
end
else
domoticz.log("Fichier introuvable",domoticz.LOG_ERROR)
end
elseif(item.name == LancementCharge and item.bState == true)then
domoticz.log("Lancement de la charge",domoticz.LOG_DEBUG)
os.execute("python3 '"..scriptPython.."' '"..credentials.."' 'start' &")
elseif(item.name == lanceAC and item.bState == true)then
domoticz.log("Lancement de la clim",domoticz.LOG_DEBUG)
os.execute("python3 '"..scriptPython.."' '"..credentials.."' 'ACstart' &")
elseif(item.name == lanceAC and item.bState == false)then
domoticz.log("Arrêt de la clim",domoticz.LOG_DEBUG)
os.execute("python3 '"..scriptPython.."' '"..credentials.."' 'ACstop' &")
elseif(item.name == chargeMode and item.bState == true)then
domoticz.log("Planning de charge activé",domoticz.LOG_DEBUG)
os.execute(scriptPython..' '..credentials..' "chargeSchedule" "'..planningActive..'" &')
elseif(item.name == chargeMode and item.bState == false)then
domoticz.log("Planning de charge désactivé",domoticz.LOG_DEBUG)
os.execute(scriptPython..' '..credentials..' "chargeSchedule" "'..planningDesactive..'" &')
elseif(item.isTimer) then
-- Suppression de l'ancien fichier et création du nouveau
os.execute("sudo rm "..fichierTemp.."' ")
os.execute("python3 '"..scriptPython.."' '"..credentials.."' '"..fichierTemp.."' &")
domoticz.emitEvent('delayed').afterSec(30)
end
end
}
Vous pouvez adapter l'heure de début et la durée en minutes
/home/pi/domoticz/scripts/python/chargeSchedule.json
Code : Tout sélectionner
{
"data":{
"type":"ChargeSchedule",
"attributes":{
"schedules":[
{
"id":1,
"activated":true,
"monday":{
"startTime":"T23:45Z",
"duration":405
},
"tuesday":{
"startTime":"T23:45Z",
"duration":405
},
"wednesday":{
"startTime":"T23:45Z",
"duration":405
},
"thursday":{
"startTime":"T23:45Z",
"duration":405
},
"friday":{
"startTime":"T23:45Z",
"duration":405
},
"saturday":{
"startTime":"T23:45Z",
"duration":405
},
"sunday":{
"startTime":"T23:45Z",
"duration":405
}
},
{
"id":2,
"activated":false
},
{
"id":3,
"activated":false
},
{
"id":4,
"activated":false
},
{
"id":5,
"activated":false
}
]
}
}
}/home/pi/domoticz/python/chargeScheduleFalse.json
Code : Tout sélectionner
{
"data":{
"type":"ChargeSchedule",
"attributes":{
"schedules":[
{
"id":1,
"activated":false,
"monday":{
"startTime":"T23:45Z",
"duration":405
},
"tuesday":{
"startTime":"T23:45Z",
"duration":405
},
"wednesday":{
"startTime":"T23:45Z",
"duration":405
},
"thursday":{
"startTime":"T23:45Z",
"duration":405
},
"friday":{
"startTime":"T23:45Z",
"duration":405
},
"saturday":{
"startTime":"T23:45Z",
"duration":405
},
"sunday":{
"startTime":"T23:45Z",
"duration":405
}
},
{
"id":2,
"activated":false
},
{
"id":3,
"activated":false
},
{
"id":4,
"activated":false
},
{
"id":5,
"activated":false
}
]
}
}
}/home/pi/domoticz/scripts/dzVents/scripts/zoeLOA.lua
Code : Tout sélectionner
--date d'acquisition/début de la LOA-LLD
local jour = 4
local mois = 1
local annee = 2020
local kilometrageAnnuel = 12500 --forfait kilométrique annuel
local alertSensor = "Moyenne Zoé" --capteur de type Alerte
local compteurKm = "Zoé" --kilométrage
return {
active = true,
logging = {
--level = domoticz.LOG_DEBUG, -- Uncomment to override the dzVents global logging setting
marker = 'Moyenne Zoé'..' '..'1.0'
},
on = {devices =
{compteurKm}, -- mise à jour en temps réel
timer = {'at 01:06'}, -- mise à jour journalière (quand la voiture ne roule pas)
},
execute = function(domoticz,compteur)
compteur = domoticz.devices(compteurKm)
domoticz.log("Kilometrage : "..compteur.counter,domoticz.LOG_INFO)
kilometrage = compteur.counter
reference = os.time{day=jour, year=annee, month=mois, hour=0, min=0, sec=0}
daysfrom = (os.difftime(os.time(), reference)-(1*60*60)) / (24 * 60 * 60) -- seconds in a day
wholedays = math.floor(daysfrom)
distanceMoyenneSouhaitee = kilometrageAnnuel/365
distanceMoyenneReelle = kilometrage/wholedays
depassement = domoticz.utils.round(kilometrage-(wholedays*distanceMoyenneSouhaitee),0)
prix = depassement/10
domoticz.log("Ancienneté : "..wholedays,domoticz.LOG_INFO)
domoticz.log("Distance moyenne journalière souhaitée : "..distanceMoyenneSouhaitee,domoticz.LOG_INFO)
domoticz.log("Distance moyenne journalière réelle : "..distanceMoyenneReelle,domoticz.LOG_INFO)
if (distanceMoyenneReelle > distanceMoyenneSouhaitee*1.01)then
domoticz.log("Moyenne trop importante !",domoticz.LOG_INFO)
domoticz.devices(alertSensor).updateAlertSensor(domoticz.ALERTLEVEL_ORANGE, 'Delta : '..depassement..' - '..prix..'€')
else
domoticz.devices(alertSensor).updateAlertSensor(domoticz.ALERTLEVEL_GREEN, 'Delta : '..depassement)
end
end
}Il est possible d'adapter le script pour d'autres lieux.
zoeLocalisation.lua
Code : Tout sélectionner
local scriptName = 'ZoéLocalisation'
local scriptVersion = '1.1'
local fichierTemp = "/var/tmp/zoe.txt"
local presence = "Zoé Domicile" -- Interrupteur
local fichierZoe = "Fichier Zoé" -- Interrupteur ativé après 30 secondes
return {
active = true,
logging = {
level = domoticz.LOG_DEBUG, -- Uncomment to override the dzVents global logging setting
marker = scriptName..' '..scriptVersion
},
on = {
--timer = {'every 5 minutes'},
devices = {
fichierZoe,
},
customEvents =
{
'delayed',
},
},
execute = function(domoticz, item)
local latitudeCible = domoticz.settings.location.latitude
local longitudeCible = domoticz.settings.location.longitude
local function readLuaFromJsonFile(fileName)
local file = io.open(fileName, 'r')
if file then
local contents = file:read('*a')
-- convertion en JSON respectant les normes
local lua_value = domoticz.utils.fromJSON(contents:gsub("\"",''):gsub("'",'"'):gsub("False","false"):gsub("True","true"):gsub("None",'"None"'))
io.close(file)
return lua_value
end
return nil
end
-- Fonction de calcul de distance
-- Renvoi la distance en kilometre a une decimale entre deux coordonées GPS
local function distancekm(latitude1, longitude1, latitude2, longitude2)
rayonTerre = 6378137; -- Rayon équatorial de la terre en metre
radlatx = math.rad(latitude1);
radlonx = math.rad(longitude1);
radlaty = math.rad(latitude2);
radlony = math.rad(longitude2);
calculLatitude = (radlaty - radlatx) / 2;
calculLongitude = (radlony - radlonx) / 2;
detail = (math.sin(calculLatitude))^2 + math.cos(radlatx) * math.cos(radlaty) * (math.sin(calculLongitude))^2;
calcul = 2 * math.atan(math.sqrt(detail), math.sqrt(1 - detail));
output = math.floor((rayonTerre * calcul)/10)/100
return output
end
zoe = readLuaFromJsonFile(fichierTemp)
if(zoe)then
if (zoe.location.data) then
latitude = zoe.location.data.attributes.gpsLatitude
domoticz.log("Latitude "..latitude, domoticz.LOG_DEBUG)
longitude = zoe.location.data.attributes.gpsLongitude
domoticz.log("Longitude "..longitude, domoticz.LOG_DEBUG)
distance = distancekm(latitude,longitude,latitudeCible,longitudeCible)
domoticz.log("distance "..distance, domoticz.LOG_DEBUG)
if(distance<1)then
domoticz.devices(presence).switchOn().checkFirst()
else
domoticz.devices(presence).switchOff().checkFirst()
end
end
else
domoticz.log("Fichier introuvable",domoticz.LOG_ERROR)
end
end
}
EN BETA POUR L'INSTANT
Ma zoé est programmée pour lancé la charge de 23h45 à 6h30.
23h45 : fin maximum de chauffe de mon Ballon d'Eau Chaude
6h30 : fin de mes heures creuses
Le but est de lancer la charge quand mon BEC a terminé plus tôt.
Nécessite une téléinfo ou un retour de puissance consommée en temps réel.
/home/pi/domoticz/scripts/dzVents/scripts/smartZoe.lua
Code : Tout sélectionner
local scriptName = 'SmartChargeZoé'
local scriptVersion = '1.2'
local puissance = 3500 --Puissance max pour déclancher la charge. Au dessus, le BEC chauffe, on ne force pas la charge.
local chargeMax = 100 --charge max
return {
active = true,
logging = {
level = domoticz.LOG_DEBUG, -- Uncomment to override the dzVents global logging setting
marker = scriptName..' '..scriptVersion
},
on = {
timer = {'at 22:35-06:30 every 1 minutes'}, -- A modifier selon votre consommation et période HC/HP
--timer = {'at 19:20-23:45 every 1 minutes'},
devices = {'Heures Creuses'},
},
execute = function(domoticz, item)
domoticz.log("Puissance : "..domoticz.devices("TeleInfo").usage, domoticz.LOG_INFO)
domoticz.log("Charge Programmée : "..domoticz.devices("Charge Programmée").state, domoticz.LOG_INFO)
domoticz.log("Zoé Branchée : "..domoticz.devices("Zoé Branchée").state, domoticz.LOG_INFO)
domoticz.log("Batterie Zoé : "..domoticz.devices("Batterie Zoé").state, domoticz.LOG_INFO)
domoticz.log("Lancer la Charge : "..domoticz.devices("Lancer la Charge").state, domoticz.LOG_INFO)
if (domoticz.devices("TeleInfo").usage < puissance -- Puissance max requise
and domoticz.devices("Charge Programmée").active == true -- Charge Programmée activée
and domoticz.devices("Lancer la Charge").active == false -- Charge pas encore lancée
and domoticz.devices("Batterie Zoé").percentage < chargeMax -- Batterie pas assez chargée
and domoticz.devices("Zoé Branchée").active == true -- Zoé branchée
and domoticz.devices("Charge Zoé").state ~= "En Charge" -- Zoé pas en charge
and item.isTimer ) then -- dans la plage horaire de lancement
--désactive la charge programmée
domoticz.devices("Charge Programmée").switchOff()
--lance la charge 2 minutes plus tard puis 5 fois toutes les minutes
domoticz.devices("Lancer la Charge").switchOn().afterMin(2).repeatAfterMin(1, 5)
domoticz.log("Démarrage forcé de la charge", domoticz.LOG_INFO)
domoticz.notify("Domobox","Démarrage anticipé de la charge de Zoé.",domoticz.PRIORITY_NORMAL)
elseif (domoticz.devices("Charge Zoé").state == "En Charge") -- Zoé est en charge
and (domoticz.devices("Charge Désactivée").active == false ) -- Charge pas encore désactivée
and (domoticz.devices("Batterie Zoé").percentage >= chargeMax -- Batterie assez chargée (consigne atteinte)
and item.isTimer )then -- dans la plage horaire de lancement
-- force l'arrêt de la charge
domoticz.devices("Charge Désactivée").switchOn()
domoticz.notify("Domobox","Arrêt forcé de la charge de Zoé.",domoticz.PRIORITY_NORMAL)
elseif ((domoticz.devices("Charge Désactivée").active == true -- Charge désactivée
or domoticz.devices("Charge Programmée").active == false) -- Charge programmée désactivée
and domoticz.devices("Heures Creuses").active == false -- heure pleine
and item.isTimer == false )then -- lancé au passage en heures pleines
-- réactive la charge
domoticz.devices("Charge Désactivée").switchOff().silent()
-- remet le planning original
domoticz.devices("Charge Programmée").switchOn().repeatAfterMin(1, 5)
-- remet le bouton de lacement de charge à l'état off
domoticz.devices("Lancer la Charge").switchOff().checkFirst()
end
end
}Bugs connus :
- L'api Renault met du temps à s'activer après la livraison. Il m'a fallu 3 semaines pour avoir tous les services d'activés.
- Le lancement de charge ne fonctionne que si le planning de charge est désactivé.
- Parfois, l'api ne fonctionne pas. C'est de plus en plus rare, mais ça arrive.
- L'actualisation peut prendre du temps suivant la couverture réseau de la voiture.
Et les icônes pour faire joli