@akamming
I just tried the Volvo.lua script found within the plugin directory
- missing availabilityStatusDevice='Volvo-availabilityStatus' in the plugin
- log showing error: 2025-01-07 00:04:28.116 Error: EventSystem: Lua script Volvo warning did not return a commandArray
is this still experimental?
Python Plugin: Volvo EV
Moderator: leecollings
-
- Posts: 539
- Joined: Sunday 01 November 2015 22:45
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 2023.2
- Location: Twente
- Contact:
Re: Python Plugin: Volvo EV
Bugs bug me.
-
- Posts: 344
- Joined: Friday 17 August 2018 14:03
- Target OS: Raspberry Pi / ODroid
- Domoticz version:
- Contact:
Re: Python Plugin: Volvo EV
impossible to troubleshoot if you don't post the logging. First Guess is that you renamed the volvo availability status device and did not change the script accordingly
I did notice that after a recent change i also neede to change the LUA, but forgot to checkin in github. So i just did.
It is now a working script (but just a sample. Adjust to your own needs). Make sure the device numbers or names match in the top of the script match your configuration, otherwise it will not work ofcourse..
Better to ask help then in the dzvents section of this forum
I did notice that after a recent change i also neede to change the LUA, but forgot to checkin in github. So i just did.
It is now a working script (but just a sample. Adjust to your own needs). Make sure the device numbers or names match in the top of the script match your configuration, otherwise it will not work ofcourse..
Better to ask help then in the dzvents section of this forum
-
- Posts: 539
- Joined: Sunday 01 November 2015 22:45
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 2023.2
- Location: Twente
- Contact:
Re: Python Plugin: Volvo EV
With the ideas and setup of myself and the help of Claude I present you my EV Consumption script.
What is needed
- a text sensor named EV Consumption Facts (Facts added to avoid naming problems within Domoticz)
- a switch sensor type doorbell with the name Reset EV Data
- you will have to create a file EV_Consumption.csv to start with in your /home/pi directory
- the contens of the file are these
and the script
EDIT 08-02-2025
I have done some cleaning up in the file and added Normalised kWh.
When charging state ~= TARGET_BATTERY_PERCENTAGE, partialkWh will be calculated to TARGET_BATTERY_PERCENTAGE.
In this way cuurent EV Consumtion is quite accurate.
The length of the script has shrunk from 404 to 256 lines
Here are the data that are displayed:
Current Odometer: 17349 km
Battery Level: 56 %
Distance February: 99 km
kWh February: 5.85 kWh
Costs February: 1.46 €
Average Temp: 2.8°C
EV Consumption: 26.66 kWh/100km
Battery level normalized to 82%
Original kWh loaded: 5.85 kWh
Normalized kWh: 26.39 kWh
What is needed
- a text sensor named EV Consumption Facts (Facts added to avoid naming problems within Domoticz)
- a switch sensor type doorbell with the name Reset EV Data
- you will have to create a file EV_Consumption.csv to start with in your /home/pi directory
- the contens of the file are these
Code: Select all
timeStamp;odometer;batteryLevel;deltaDistance;kWhTotal;deltakWh;kWh100km;euro;a>
01-01-2025 01:00;15513;;;2562.958;;;;
Code: Select all
-- Data is written to file and to textSensor
-- file: EV_Consumption.csv, textSensor EV Consumption
-- monthly data are saved to file at the end of each Month
-- it enables you to depict the relationship between EV Consumption and temperature
-- Constants
local CONSTANTS = {
BATTERY_CAPACITY = 79, -- kWh
TARGET_BATTERY_PERCENTAGE = 82, -- Target percentage for normalization
PRICE_PER_KWH = 0.25, -- euro/kWh
CSV_FILE_PATH = "/home/pi/EV_Consumption.csv", -- Path to the CSV file
MAX_TEMP_ARRAY_SIZE = 1440 -- Max number of temperature measurements (1 day with 1 measurement per minute)
}
-- Helper functions
local function spaces(count)
return string.rep(" ", count)
end
local function round2Decimals(number)
if number == nil then
return 0
end
return math.floor(number * 100 + 0.5) / 100
end
-- Check if today is the last day of the month
local function isLastDayOfMonth()
local today = os.date("*t")
local tomorrow = os.date("*t", os.time() + 24 * 60 * 60)
return today.month ~= tomorrow.month
end
-- Format display text for the text device
local function formatDisplayText(domoticz, data, currentMonth)
-- Ensure domoticz.log is available
if domoticz and domoticz.log then
-- Log all data for debugging
domoticz.log('Last Update: ' .. (data.lastUpdate or "N/A"), domoticz.LOG_DEBUG)
domoticz.log('Current Odometer: ' .. (tonumber(data.currentOdometer) or 0) .. ' km', domoticz.LOG_DEBUG)
domoticz.log('Battery Level: ' .. (tonumber(data.batteryLevel) or 0) .. ' %', domoticz.LOG_DEBUG)
domoticz.log('Distance ' .. currentMonth .. ': ' .. (tonumber(data.distance) or 0) .. ' km', domoticz.LOG_DEBUG)
domoticz.log('kWh ' .. currentMonth .. ': ' .. (tonumber(data.kWhPartial) or 0) .. ' kWh', domoticz.LOG_DEBUG)
domoticz.log('Costs ' .. currentMonth .. ': ' .. (tonumber(data.euro) or 0) .. ' €', domoticz.LOG_DEBUG)
domoticz.log('Average Temp: ' .. (tonumber(data.avgTemp) or 0) .. '°C', domoticz.LOG_DEBUG)
domoticz.log('EV Consumption: ' .. (tonumber(data.evConsumption) or 0) .. ' kWh/100km', domoticz.LOG_DEBUG)
domoticz.log('Battery level normalized to ' .. CONSTANTS.TARGET_BATTERY_PERCENTAGE .. '%', domoticz.LOG_DEBUG)
domoticz.log('Original kWh loaded: ' .. (tonumber(data.kWhPartial) or 0) .. ' kWh', domoticz.LOG_DEBUG)
domoticz.log('Normalized kWh: ' .. (tonumber(data.normalizedKWh) or 0) .. ' kWh', domoticz.LOG_DEBUG)
else
-- Provide a clearer error message
local errorMsg = 'Er is een fout opgetreden in local function formatDisplayText: '
if not domoticz then
errorMsg = errorMsg .. 'domoticz is nil. '
end
if domoticz and not domoticz.log then
errorMsg = errorMsg .. 'domoticz.log is nil.'
end
domoticz.log(errorMsg, domoticz.LOG_ERROR)
end
return string.format(
"Last Update : %s\n" ..
"Current Odometer : %d km\n" ..
"Battery Level : %d %% \n" ..
"Distance %s : %d km\n" ..
"kWh %s : %.2f kWh\n" ..
spaces(15) .. "Costs %s : %.2f €\n" ..
spaces(15) .. "Average Temp : %.1f°C\n" ..
spaces(15) .. "EV Consumption : %.2f kWh/100km\n" ..
spaces(15) .. "Battery level normalized to %d%%\n" ..
spaces(15) .. "Original kWh loaded: %.2f kWh\n" ..
spaces(15) .. "Normalized kWh   : %.2f kWh\n",
data.lastUpdate or "N/A",
tonumber(data.currentOdometer) or 0,
tonumber(data.batteryLevel) or 0,
currentMonth, tonumber(data.distance) or 0,
currentMonth, tonumber(data.kWhPartial) or 0,
currentMonth, tonumber(data.euro) or 0,
tonumber(data.avgTemp) or 0,
tonumber(data.evConsumption) or 0,
CONSTANTS.TARGET_BATTERY_PERCENTAGE,
tonumber(data.kWhPartial) or 0,
tonumber(data.normalizedKWh) or 0
)
end
-- Update the text device with the latest data
local function updateDisplay(domoticz, displayText)
local displayDevice = domoticz.devices('EV Consumption Facts')
if displayDevice then
displayDevice.updateText(displayText)
domoticz.log('Text sensor updated with new data', domoticz.LOG_DEBUG)
else
domoticz.log('Text sensor "EV Consumption Facts" not found', domoticz.LOG_ERROR)
end
end
-- Normalize battery consumption to target percentage
local function normalizeToTargetLevel(domoticz, currentLevel, kWhUsed)
local kWhPerPercent = CONSTANTS.BATTERY_CAPACITY / 100
local difference = CONSTANTS.TARGET_BATTERY_PERCENTAGE - currentLevel
local kWhAdjustment = difference * kWhPerPercent
local normalizedKWh = kWhUsed + kWhAdjustment
domoticz.log('Battery normalization calculation:', domoticz.LOG_DEBUG)
domoticz.log(string.format('Current level: %.1f%%', currentLevel), domoticz.LOG_DEBUG)
domoticz.log(string.format('Difference to target: %.1f%%', difference), domoticz.LOG_DEBUG)
domoticz.log(string.format('kWh adjustment: %.2f kWh', kWhAdjustment), domoticz.LOG_DEBUG)
domoticz.log(string.format('Original kWh: %.2f, Normalized kWh: %.2f', kWhUsed, normalizedKWh), domoticz.LOG_DEBUG)
return normalizedKWh
end
-- Save data to CSV file
local function saveToCSV(data)
local file = io.open(CONSTANTS.CSV_FILE_PATH, "a")
if not file then return false end
local fields = {
os.date('%d-%m-%Y %H:%M'),
math.floor(data.currentOdometer or 0),
math.floor(data.batteryLevel or 0),
math.floor(data.distance or 0),
round2Decimals(data.kWhTotal),
round2Decimals(data.kWhPartial),
round2Decimals(data.evConsumption),
round2Decimals(data.euro),
round2Decimals(data.avgTemp)
}
local csvLine = table.concat(fields, ";") .. "\n"
file:write(csvLine)
file:close()
return true
end
-- Load data from CSV file
local function loadDataFromCSV()
local file = io.open(CONSTANTS.CSV_FILE_PATH, "r")
if not file then return nil end
-- Skip the header line
file:read("*l")
local lastLine
for line in file:lines() do
lastLine = line
end
file:close()
if not lastLine then return nil end
local fields = {}
for field in string.gmatch(lastLine, "([^;]+)") do
table.insert(fields, field)
end
return {
lastUpdate = fields[1],
beginningOfTheMonthOdometer = tonumber(fields[2]),
beginningOfTheMonthBatteryLevel = tonumber(fields[3]),
beginningOfTheMonthkWhTotal = tonumber(fields[5]),
avgTemp = tonumber(fields[9])
}
end
-- Process EV data and update display
local function processEVData(domoticz, sensorData, csvData)
local kWhPartial = sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal
local euro = kWhPartial * CONSTANTS.PRICE_PER_KWH
local distance = sensorData.currentOdometer - csvData.beginningOfTheMonthOdometer
local normalizedKWh = normalizeToTargetLevel(domoticz, sensorData.batteryLevel, kWhPartial)
local evConsumption = (distance > 0) and ((normalizedKWh / distance) * 100) or 0
-- Log for debugging
domoticz.log('kWhPartial: ' .. kWhPartial, domoticz.LOG_DEBUG)
domoticz.log('euro: ' .. euro, domoticz.LOG_DEBUG)
domoticz.log('distance: ' .. distance, domoticz.LOG_DEBUG)
domoticz.log('normalizedKWh: ' .. normalizedKWh, domoticz.LOG_DEBUG)
domoticz.log('evConsumption: ' .. evConsumption, domoticz.LOG_DEBUG)
-- Prepare display data
local displayData = {
currentOdometer = sensorData.currentOdometer,
batteryLevel = sensorData.batteryLevel,
distance = distance,
kWhPartial = kWhPartial,
kWhTotal = sensorData.currentkWhTotal,
euro = euro,
avgTemp = sensorData.temperature,
evConsumption = evConsumption,
normalizedKWh = normalizedKWh,
lastUpdate = os.date('%Y-%m-%d %H:%M:%S')
}
-- Update display
local currentMonth = os.date('%B')
local displayText = formatDisplayText(displayData, currentMonth)
updateDisplay(domoticz, displayText)
end
-- Main script
return {
on = {
devices = {'Charging Level', 'Reset EV Data'},
timer = {'at 23:56'}
},
logging = {
level = domoticz.LOG_DEBUG,
marker = "----- EV Consumption -----"
},
data = {
previousSelectorLevel = { initial = 0 }
},
execute = function(domoticz, device)
-- Load data from CSV
local csvData = loadDataFromCSV()
if not csvData then
domoticz.log('Failed to load data from CSV', domoticz.LOG_ERROR)
return
end
-- Read current sensor values
local sensorData = {
selectorLevel = domoticz.devices('Charging Level').levelVal,
batteryLevel = domoticz.devices('XC40-ChargeLevel').nValue,
currentOdometer = domoticz.devices('Volvo-Odometer').nValue,
currentkWhTotal = domoticz.devices('Laadpaal').WhTotal / 1000,
temperature = tonumber(domoticz.devices('Buitentemperatuur').sValue)
}
-- Check if Charging Level changed from > 0 to 0
if sensorData.selectorLevel == 0 and domoticz.data.previousSelectorLevel > 0 then
-- Process data and update display
processEVData(domoticz, sensorData, csvData)
end
-- Update previousSelectorLevel
domoticz.data.previousSelectorLevel = sensorData.selectorLevel
-- Save data to CSV only on the last day of the month at 23:56
if isLastDayOfMonth() and device.isTimer then
local displayData = {
currentOdometer = sensorData.currentOdometer,
batteryLevel = sensorData.batteryLevel,
distance = sensorData.currentOdometer - csvData.beginningOfTheMonthOdometer,
kWhPartial = sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal,
kWhTotal = sensorData.currentkWhTotal,
euro = (sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal) * CONSTANTS.PRICE_PER_KWH,
avgTemp = sensorData.temperature,
evConsumption = (sensorData.currentOdometer - csvData.beginningOfTheMonthOdometer > 0) and (((sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal) / (sensorData.currentOdometer - csvData.beginningOfTheMonthOdometer)) * 100) or 0,
normalizedKWh = normalizeToTargetLevel(domoticz, sensorData.batteryLevel, sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal),
lastUpdate = os.date('%Y-%m-%d %H:%M:%S')
}
saveToCSV(displayData)
end
end
}
I have done some cleaning up in the file and added Normalised kWh.
When charging state ~= TARGET_BATTERY_PERCENTAGE, partialkWh will be calculated to TARGET_BATTERY_PERCENTAGE.
In this way cuurent EV Consumtion is quite accurate.
The length of the script has shrunk from 404 to 256 lines
Here are the data that are displayed:
Current Odometer: 17349 km
Battery Level: 56 %
Distance February: 99 km
kWh February: 5.85 kWh
Costs February: 1.46 €
Average Temp: 2.8°C
EV Consumption: 26.66 kWh/100km
Battery level normalized to 82%
Original kWh loaded: 5.85 kWh
Normalized kWh: 26.39 kWh
Bugs bug me.
-
- Posts: 539
- Joined: Sunday 01 November 2015 22:45
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 2023.2
- Location: Twente
- Contact:
Re: Python Plugin: Volvo EV
Any idea what this is supposed to mean?
2025-02-13 13:10:10.201 Error: Volvo hardware (16) thread seems to have ended unexpectedly
2025-02-13 13:10:24.204 Error: Volvo hardware (16) thread seems to have ended unexpectedly
2025-02-13 13:10:38.207 Error: Volvo hardware (16) thread seems to have ended unexpectedly
2025-02-13 13:10:52.210 Error: Volvo hardware (16) thread seems to have ended unexpectedly
I deactivated and reactivated the plugin, no difference.
2025-02-13 13:10:10.201 Error: Volvo hardware (16) thread seems to have ended unexpectedly
2025-02-13 13:10:24.204 Error: Volvo hardware (16) thread seems to have ended unexpectedly
2025-02-13 13:10:38.207 Error: Volvo hardware (16) thread seems to have ended unexpectedly
2025-02-13 13:10:52.210 Error: Volvo hardware (16) thread seems to have ended unexpectedly
I deactivated and reactivated the plugin, no difference.
Bugs bug me.
-
- Posts: 344
- Joined: Friday 17 August 2018 14:03
- Target OS: Raspberry Pi / ODroid
- Domoticz version:
- Contact:
Re: Python Plugin: Volvo EV
This error can occur if the Volvo API takes too lojng to respond. Will probably resolve itselfHvdW wrote: ↑Thursday 13 February 2025 13:11 Any idea what this is supposed to mean?
2025-02-13 13:10:10.201 Error: Volvo hardware (16) thread seems to have ended unexpectedly
2025-02-13 13:10:24.204 Error: Volvo hardware (16) thread seems to have ended unexpectedly
2025-02-13 13:10:38.207 Error: Volvo hardware (16) thread seems to have ended unexpectedly
2025-02-13 13:10:52.210 Error: Volvo hardware (16) thread seems to have ended unexpectedly
I deactivated and reactivated the plugin, no difference.
Who is online
Users browsing this forum: No registered users and 1 guest