├── .gitignore ├── FileSets └── w1-gpio.dtbo ├── LICENSE ├── README.md ├── changes ├── dbus-i2c.py ├── gitHubInfo ├── i2c.py ├── i2c.pyc ├── raspberryPiOnly ├── screenshots ├── PackageManagerAddCustomPackage.png ├── PackageManagerAddPackage.png ├── PackageManagerInstallAktivPackage.png ├── PackageManagerMenu.png └── TempsInMenu.png ├── service ├── log │ ├── run │ └── supervise │ │ ├── lock │ │ └── status ├── run └── supervise │ ├── lock │ └── status ├── setup ├── tests ├── c2.sh └── check-i2c.sh └── version /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /FileSets/w1-gpio.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/FileSets/w1-gpio.dtbo -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, LHardwick-git 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Venus OS Temperature Service 2 | ### Fork from LHardwick Victron-Service 3 | 4 | This is a service to publish temperature type data onto the DBus of VenusOs running on a Raspberry Pi device. 5 | Note: Currently this will not display the CPU temperature on Venus GX, only on RPi. 6 | 7 | Added Support to install this with Kevin Windrem's Venus OS Setup Helper (https://github.com/kwindrem/SetupHelper) 8 | 9 | ## INSTALL INSTRUCTIONS 10 | No Settings needed for 1 Wire (e.g. DS18B20) all you need is to install SetupHelper and configure a custom Package. 11 | - Package name: VenusOS-TemperatureService 12 | - GitHub user: Rikkert-RS 13 | - GitHub Tag: latest 14 | 15 | ### Screenshots 16 |
Add Custom Package 17 | 18 | ![PackageManager Menü](/screenshots/PackageManagerMenu.png) 19 | ![Add Custom Package ](/screenshots/PackageManagerAddPackage.png) 20 | ![Fill Custom Package](/screenshots/PackageManagerAddCustomPackage.png) 21 | ![Install Package](/screenshots/PackageManagerInstallAktivPackage.png) 22 | 23 |
24 | 25 | ### Enabled Features in this Setup: 26 | - Raspberry Pi CPU temperature 27 | - 1-Wire Support (Temperatures) Data Port GPIO 26 on RPi 28 | 29 | Please keep in mind that there can always be conflicts with the GPIO's. Depending on what hardware you have (CAN hat etc) 30 | The 1Wire GPIO Port can be adjusted in u-boot/config.txt after install 31 | 32 | ### Can be activated but not tested (in dbus-i2c.py) 33 | - i2c Sensors 34 | - ADC Sensors 35 | 36 | Tested on Rasberry 3+ with Venus OS 2.91 37 | 38 | ### Own Services: 39 | Note, only services of path type "Temperature" will be displayed on the console and VRM 40 | If you modify the service to pubish data as a path that is of a different type 41 | it will only be available via the DBus and will not appear on the console or VRM. 42 | 43 | ![Temps in Venus OS Menu](/screenshots/TempsInMenu.png) 44 | 45 | Hope this all works for you 46 | 47 | Rikkert-RS 48 | -------------------------------------------------------------------------------- /changes: -------------------------------------------------------------------------------- 1 | v0.53: 2 | Fixed install issue with Update Setup for SetupHelper HelperResources 3 | v0.52: 4 | Fixed Service crashes if no 1Wire Sensor is connected (only use CPU Temp) 5 | Optimized Setup Scipt for install and uninstall 6 | v0.51: 7 | Correction for No negative numbers were displayed 8 | v0.5: 9 | Fixed issue #4 Temperatures freezing when inactive 10 | Fixed issue #3 Phantom of the temperature probe 11 | Settings ID is now set to 1-Wire device ID so it is no longer related to VRM instance ID 12 | Default gpio pin changed from 4 to 26 due to CAN Hat collision 13 | v0.4: 14 | Fork from LHardwick-git/Victron-Service, with support to Kevin Windrem's Setuphelper 15 | -------------------------------------------------------------------------------- /dbus-i2c.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2021 LHardwick-git Edit by Rikkert-RS 4 | # Licensed under the BSD 3-Clause license. See LICENSE file in the project root for full license information. 5 | # 6 | # takes data from the i2c and adc channels (which are not used by venus) and publishes the data on the bus. 7 | 8 | # If edditing then use 9 | # svc -d /service/VenusOS-TemperatureService and 10 | # svc -u /service/VenusOS-TemperatureService 11 | # to stop and restart the service 12 | 13 | #--------------------- support python 2 and 3 14 | import sys 15 | if sys.version_info.major == 3: 16 | python3 = True 17 | else: 18 | python3 = False 19 | 20 | from dbus.mainloop.glib import DBusGMainLoop 21 | 22 | if python3: 23 | from gi.repository import GLib # for Python 3 24 | else: 25 | from gobject import idle_add 26 | import gobject as GLib 27 | #--------------------- 28 | 29 | import dbus 30 | import dbus.service 31 | import inspect 32 | import platform 33 | from threading import Timer 34 | import argparse 35 | import logging 36 | import os 37 | from pprint import pprint 38 | #--------------------- 39 | # Import i2c interface driver, this is a modified library stored in the same directory as this file 40 | from i2c import AM2320 as AM2320 41 | 42 | # our own packages 43 | sys.path.insert(1, os.path.join(os.path.dirname(__file__), '/opt/victronenergy/dbus-modem')) 44 | from vedbus import VeDbusService, VeDbusItemExport, VeDbusItemImport 45 | from settingsdevice import SettingsDevice # available in the velib_python repository 46 | 47 | SCount = 0 48 | dbusservice = None 49 | 50 | def update(): 51 | # Calls to update ADC and I2C interfaces have been commented out 52 | # The is in case someone runes this who does not know what they are doing 53 | # and does not have i2c devices and/or does not want or have the extra ADC channels. 54 | # I have left the code in in case you wanton enable them 55 | # 56 | # So the only service left running is the Raspberry pi CPU temperature. 57 | # 58 | update_rpi() 59 | update_W1() 60 | # update_i2c() 61 | # update_adc() 62 | return True 63 | 64 | # update i2c interface values 65 | def update_i2c(): 66 | if not os.path.exists('/dev/i2c-1'): 67 | if dbusservice['i2c-humidity']['/Connected'] != 0: 68 | logging.info("i2c interface disconnected") 69 | dbusservice['i2c-humidity']['/Connected'] = 0 70 | dbusservice['i2c-temperature']['/Connected'] = 0 71 | logging.info("i2c bus not available") 72 | else: 73 | am2320 = AM2320(1) 74 | (t,h,e, report) = am2320.readSensor() 75 | # Returns temperature, humidity, error ststus, and text report 76 | if e != 0: 77 | logging.info("Error in i2c bus read, "+ report) 78 | dbusservice['i2c-humidity']['/Status'] = e 79 | dbusservice['i2c-temp']['/Status'] = e 80 | dbusservice['i2c-humidity']['/Humidity'] = [] 81 | dbusservice['i2c-temp']['/Temperature'] = [] 82 | else: 83 | if dbusservice['i2c-humidity']['/Connected'] != 1: 84 | logging.info("i2c bus device connected") 85 | dbusservice['i2c-humidity']['/Connected'] = 1 86 | dbusservice['i2c-temp']['/Connected'] = 1 87 | dbusservice['i2c-humidity']['/Status'] = 0 88 | dbusservice['i2c-temp']['/Status'] = 0 89 | logging.debug("values now are temperature %s, humidity %s" % (t, h)) 90 | dbusservice['i2c-humidity']['/Humidity'] = h 91 | dbusservice['i2c-temp']['/Temperature'] = t 92 | 93 | def update_adc(): 94 | # update adc interface values 95 | # scale is hard coded here but could be implemented as a /scale setting in the dbus object 96 | scale = 1 97 | 98 | # the device iio:device 0 is the device running all adc channels 99 | # there are repeated calls here to check the device exists to set the ststus for every channel 100 | # it is assumed there is little overhead in this repeated call to the system. 101 | 102 | for channel in [0, 1, 7]: 103 | if not os.path.exists('/sys/bus/iio/devices/iio:device0'): 104 | if dbusservice['adc-temp'+str(channel)]['/Connected'] != 0: 105 | logging.info("adc interface disconnected") 106 | dbusservice['adc-temp'+str(channel)]['/Connected'] = 0 107 | else: 108 | if dbusservice['adc-temp'+str(channel)]['/Connected'] != 1: 109 | logging.info("adc interface channel " + str(channel) + " connected") 110 | dbusservice['adc-temp'+str(channel)]['/Connected'] = 1 111 | fd = open('/sys/bus/iio/devices/iio:device0/in_voltage'+str(channel)+'_raw','r') 112 | 113 | value = 0 114 | for loop in range (0,10): 115 | value += int(fd.read()) 116 | fd.seek(0) 117 | fd.close 118 | value = value / 10 119 | value = dbusservice['adc-temp'+str(channel)]['/Offset']+round(2.1+(value-2015)*0.135*scale,1) 120 | # logging.info(" Temperature "+str(value)) 121 | # added stuff here for short circuit and disconnect status 122 | if value > 140: 123 | dbusservice['adc-temp'+str(channel)]['/Status'] = 1 124 | dbusservice['adc-temp'+str(channel)]['/Temperature'] = [] 125 | elif value < -100: 126 | dbusservice['adc-temp'+str(channel)]['/Status'] = 2 127 | dbusservice['adc-temp'+str(channel)]['/Temperature'] = [] 128 | else: 129 | dbusservice['adc-temp'+str(channel)]['/Status'] = 0 130 | dbusservice['adc-temp'+str(channel)]['/Temperature'] = value 131 | 132 | 133 | 134 | # update Pi CPU temperature 135 | def update_rpi(): 136 | if not os.path.exists('/sys/devices/virtual/thermal/thermal_zone0/temp'): 137 | if dbusservice['cpu-temp']['/Connected'] != 0: 138 | logging.info("cpu temperature interface disconnected") 139 | dbusservice['cpu-temp']['/Connected'] = 0 140 | else: 141 | if dbusservice['cpu-temp']['/Connected'] != 1: 142 | logging.info("cpu temperature interface connected") 143 | dbusservice['cpu-temp']['/Connected'] = 1 144 | fd = open('/sys/devices/virtual/thermal/thermal_zone0/temp','r') 145 | value = float(fd.read()) 146 | value = round(value / 1000.0, 1) 147 | dbusservice['cpu-temp']['/Temperature'] = value 148 | fd.close 149 | 150 | #update W1 temp 151 | def update_W1(): 152 | #check, create and update 1 Wire devices 153 | 154 | #read list of slaves 155 | if os.path.isfile('/sys/devices/w1_bus_master1/w1_master_slaves'): 156 | fd = open('/sys/devices/w1_bus_master1/w1_master_slaves','r') 157 | w1Slaves = fd.read().splitlines() 158 | fd.close 159 | 160 | #Loop through all connected 1Wire devices, create dbusService if necessary 161 | for id in w1Slaves: 162 | familyID = id[0:2] 163 | deviceID = id[3:] 164 | logging.debug("1Wire Family ID:" + familyID + " Full DevicesID:" + id) 165 | 166 | #DS18B20 Temp Sensors 167 | if familyID == '28': 168 | if ('W1-temp:'+ id) not in dbusservice: 169 | logging.info("1Wire Sensor found with no Service -> Create:") 170 | 171 | dbusservice['W1-temp:'+ id] = new_service(base, 'temperature', 'Wire', '1Wire', SCount+1, 100+SCount, deviceID) 172 | dbusservice['W1-temp:'+ id]['/ProductName'] = '1Wire Sensor ' + id 173 | dbusservice['W1-temp:'+ id]['/HardwareVersion'] = deviceID 174 | dbusservice['W1-temp:'+ id]['/FirmwareVersion'] = familyID 175 | initSettings(newSettings) 176 | readSettings(settingObjects) 177 | logging.info("Created Service 1Wire ID: " + str(SCount) + " Settings ID:" + str(SCount)) 178 | 179 | #read Temp value 180 | value = None #invalidate value 181 | if os.path.exists('/sys/devices/w1_bus_master1/'+ id +'/temperature'): 182 | fd = open('/sys/devices/w1_bus_master1/'+ id +'/temperature','r') 183 | lines = fd.read().splitlines() 184 | if lines: 185 | logging.debug("RawValue ID" + id + ":" + lines[0]) 186 | if lines[0].strip('-').isnumeric(): 187 | value = float(lines[0]) 188 | value = round(value / 1000.0, 1) 189 | fd.close 190 | 191 | dbusservice['W1-temp:'+ id]['/Temperature'] = value 192 | 193 | #Check 1 Wire Service Connection 194 | for item in dbusservice: 195 | logging.debug("Search for 1Wire Service Current Service: " + item) 196 | if dbusservice[item]['/Mgmt/Connection'] == '1Wire': 197 | logging.debug("Found 1 Wire Service Check connection") 198 | if not os.path.exists('/sys/devices/w1_bus_master1/'+ item[8:]): 199 | if dbusservice[item]['/Connected'] != 0: 200 | logging.info(item + " temperature interface disconnected") 201 | dbusservice[item]['/Connected'] = 0 202 | dbusservice[item]['/Status'] = 1 203 | dbusservice[item]['/Temperature'] = None 204 | else: 205 | if dbusservice[item]['/Connected'] != 1: 206 | logging.info(item + " temperature interface connected") 207 | dbusservice[item]['/Connected'] = 1 208 | dbusservice[item]['/Status'] = 0 209 | 210 | 211 | # =========================== Start of settings interface ================ 212 | # The settings interface handles the persistent storage of changes to settings 213 | # This should probably be created as a new class extension to the settingDevice object 214 | # The complexity is because this python service handles temperature and humidity 215 | # Data for about 6 different service paths so we need different dBusObjects for each device 216 | # 217 | newSettings = {} # Used to gather new settings to create/check as each dBus object is created 218 | settingObjects = {} # Used to identify the dBus object and path for each setting 219 | # settingsObjects = {setting: [path,object],} 220 | # each setting is the complete string e.g. /Settings/Temperature/4/Scale 221 | 222 | settingDefaults = {'/Offset': [0, -10, 10], 223 | '/Scale' : [1.0, -5, 5], 224 | '/TemperatureType' : [0, 0, 3], 225 | '/CustomName' : ['', 0, 0]} 226 | 227 | # Values changed in the GUI need to be updated in the settings 228 | # Without this changes made through the GUI change the dBusObject but not the persistent setting 229 | # (as tested in venus OS 2.54 August 2020) 230 | def handle_changed_value(setting, path, value): 231 | global settings 232 | print("some value changed") 233 | # The callback to the handle value changes has been modified by using an anonymouse function (lambda) 234 | # the callback is declared each time a path is added see example here 235 | # self.add_path(path, 0, writeable=True, onchangecallback = lambda x,y: handle_changed_value(setting,x,y) ) 236 | logging.info(" ".join(("Storing change to setting", setting+path, str(value) )) ) 237 | settings[setting+path] = value 238 | return True 239 | 240 | # Changes made to settings need to be reflected in the GUI and in the running service 241 | def handle_changed_setting(setting, oldvalue, newvalue): 242 | logging.info('Setting changed, setting: %s, old: %s, new: %s' % (setting, oldvalue, newvalue)) 243 | [path, object] = settingObjects[setting] 244 | object[path] = newvalue 245 | return True 246 | 247 | # Add setting is called each time a new service path is created that needs a persistent setting 248 | # If the setting already exists the existing recored is unchanged 249 | # If the setting does not exist it is created when the serviceDevice object is created 250 | def addSetting(base, path, dBusObject): 251 | global settingObjects 252 | global newSettings 253 | global settingDefaults 254 | setting = base + path 255 | logging.info(" ".join(("Add setting", setting, str(settingDefaults[path]) )) ) 256 | settingObjects[setting] = [path, dBusObject] # Record the dBus Object and path for this setting 257 | newSettings[setting] = [setting] + settingDefaults[path] # Add the setting to the list to be created 258 | 259 | # initSettings is called when all the required settings have been added 260 | def initSettings(newSettings): 261 | global settings 262 | 263 | # settingsDevice is the library class that handles the reading and setting of persistent settings 264 | settings = SettingsDevice( 265 | bus=dbus.SystemBus() if (platform.machine() == 'armv7l') else dbus.SessionBus(), 266 | supportedSettings = newSettings, 267 | eventCallback = handle_changed_setting) 268 | 269 | # readSettings is called after init settings to read all the stored settings and 270 | # set the initial values of each of the service object paths 271 | # Note you can not read or set a setting if it has not be included in the newSettings 272 | # list passed to create the new settingsDevice class object 273 | 274 | def readSettings(list): 275 | global settings 276 | for setting in list: 277 | [path, object] = list[setting] 278 | logging.info(" ".join(("Retreived setting", setting, path, str(settings[setting])))) 279 | object[path] = settings[setting] 280 | 281 | 282 | # =========================== end of settings interface ====================== 283 | 284 | class SystemBus(dbus.bus.BusConnection): 285 | def __new__(cls): 286 | return dbus.bus.BusConnection.__new__(cls, dbus.bus.BusConnection.TYPE_SYSTEM) 287 | 288 | class SessionBus(dbus.bus.BusConnection): 289 | def __new__(cls): 290 | return dbus.bus.BusConnection.__new__(cls, dbus.bus.BusConnection.TYPE_SESSION) 291 | 292 | def dbusconnection(): 293 | return SessionBus() if 'DBUS_SESSION_BUS_ADDRESS' in os.environ else SystemBus() 294 | 295 | 296 | # Argument parsing 297 | parser = argparse.ArgumentParser(description='dbusMonitor.py demo run') 298 | parser.add_argument("-n", "--name", help="the D-Bus service you want me to claim", type=str, default="com.victronenergy.i2c") 299 | parser.add_argument("-i", "--deviceinstance", help="the device instance you want me to be", type=str, default="0") 300 | parser.add_argument("-d", "--debug", help="set logging level to debug", action="store_true") 301 | args = parser.parse_args() 302 | 303 | #args.debug = True 304 | 305 | # Init logging 306 | logging.basicConfig(level=(logging.DEBUG if args.debug else logging.INFO)) 307 | if python3: 308 | logging.info(__file__ + " is starting up - python 3") 309 | else: 310 | logging.info(__file__ + " is starting up - python 2") 311 | logLevel = {0: 'NOTSET', 10: 'DEBUG', 20: 'INFO', 30: 'WARNING', 40: 'ERROR'} 312 | logging.info('Loglevel set to ' + logLevel[logging.getLogger().getEffectiveLevel()]) 313 | 314 | # Have a mainloop, so we can send/receive asynchronous calls to and from dbus 315 | DBusGMainLoop(set_as_default=True) 316 | 317 | def new_service(base, type, physical, logical, id, instance, settingId = False): 318 | global SCount 319 | self = VeDbusService("{}.{}.{}_id{:02d}".format(base, type, physical, id), dbusconnection()) 320 | # physical is the physical connection 321 | # logical is the logical connection to allign with the numbering of the console display 322 | # Create the management objects, as specified in the ccgx dbus-api document 323 | self.add_path('/Mgmt/ProcessName', __file__) 324 | self.add_path('/Mgmt/ProcessVersion', 'Unkown version, and running on Python ' + platform.python_version()) 325 | self.add_path('/Mgmt/Connection', logical) 326 | 327 | # Create the mandatory objects, note these may need to be customised after object creation 328 | self.add_path('/DeviceInstance', instance) 329 | self.add_path('/ProductId', 0) 330 | self.add_path('/ProductName', '') 331 | self.add_path('/FirmwareVersion', 0) 332 | self.add_path('/HardwareVersion', 0) 333 | self.add_path('/Connected', 0) # Mark devices as disconnected until they are confirmed 334 | 335 | # Create device type specific objects set values to empty until connected 336 | if settingId : 337 | setting = "/Settings/" + type.capitalize() + "/" + str(settingId) 338 | else: 339 | print("no setting required") 340 | setting = "" 341 | if type == 'temperature': 342 | self.add_path('/Temperature', []) 343 | self.add_path('/Status', 0) 344 | if settingId: 345 | addSetting(setting , '/TemperatureType', self) 346 | addSetting(setting , '/CustomName', self) 347 | self.add_path('/TemperatureType', 0, writeable=True, onchangecallback = lambda x,y: handle_changed_value(setting,x,y) ) 348 | self.add_path('/CustomName', '', writeable=True, onchangecallback = lambda x,y: handle_changed_value(setting,x,y) ) 349 | self.add_path('/Function', 1, writeable=True ) 350 | if 'adc' in physical: 351 | if settingId: 352 | addSetting(setting,'/Scale',self) 353 | addSetting(setting,'/Offset',self) 354 | self.add_path('/Scale', 1.0, writeable=True, onchangecallback = lambda x,y: handle_changed_value(setting,x,y) ) 355 | self.add_path('/Offset', 0, writeable=True, onchangecallback = lambda x,y: handle_changed_value(setting,x,y) ) 356 | if type == 'humidity': 357 | self.add_path('/Humidity', []) 358 | self.add_path('/Status', 0) 359 | SCount += 1 360 | return self 361 | 362 | dbusservice = {} # Dictionary to hold the multiple services 363 | 364 | base = 'com.victronenergy' 365 | 366 | # Init setting - create setting object to read any existing settings 367 | # Init is called again later to set anything that does not exist 368 | # this gets round the Chicken and Egg bootstrap problem, 369 | 370 | # service defined by (base*, type*, connection*, logical, id*, instance, settings ID): 371 | # The setting iD is used with settingsDevice library to create a persistent setting 372 | # Items marked with a (*) are included in the service name 373 | # 374 | # I have commented out the bits that will make new services for i2C and ADC services here 375 | # If you want to re-enable these you need to uncomment the right lines 376 | # !!! Importand do NOT set an Dash in "connection" Parameter 377 | 378 | #dbusservice['i2c-temp'] = new_service(base, 'temperature', 'i2c', 'i2c Device 1', 0, 25, 7) 379 | #dbusservice['i2c-humidity'] = new_service(base, 'humidity', 'i2c', 'i2c Device 1', 0, 25) 380 | # Tidy up custom or missing items 381 | #dbusservice['i2c-temp'] ['/ProductName'] = 'Encased i2c AM2315' 382 | #dbusservice['i2c-humidity']['/ProductName'] = 'Encased i2c AM2315' 383 | 384 | #dbusservice['adc-temp0'] = new_service(base, 'temperature', 'RPi_adc0', 'Temperature sensor input 3', 0, 26, 3) 385 | #dbusservice['adc-temp1'] = new_service(base, 'temperature', 'RPi_adc1', 'Temperature sensor input 4', 1, 27, 4) 386 | #dbusservice['adc-temp7'] = new_service(base, 'temperature', 'RPi_adc7', 'Temperature sensor input 5', 2, 28, 5) 387 | # Tidy up custom or missing items 388 | #dbusservice['adc-temp0'] ['/ProductName'] = 'Custard Pi-3 8x12bit adc' 389 | #dbusservice['adc-temp1'] ['/ProductName'] = 'Custard Pi-3 8x12bit adc' 390 | #dbusservice['adc-temp7'] ['/ProductName'] = 'Custard Pi-3 8x12bit adc' 391 | 392 | # Raspy CPU Temp 393 | dbusservice['cpu-temp'] = new_service(base, 'temperature', 'RPi_cpu', 'Raspberry Pi OS', SCount+1, 100, SCount+1) 394 | # Tidy up custom or missing items 395 | if os.path.exists('/sys/firmware/devicetree/base/model'): 396 | with open('/sys/firmware/devicetree/base/model', 'r') as f: 397 | value = str(f.readline().strip('\n')) 398 | value = ''.join([c for c in value if c.isalnum() or c in [' ', '.']]) 399 | dbusservice['cpu-temp']['/ProductName'] = value 400 | else: 401 | dbusservice['cpu-temp']['/ProductName'] = 'Raspberry Pi' 402 | 403 | # Persistent settings obejects in settingsDevice will not exist before this is executed 404 | initSettings(newSettings) 405 | # Do something to read the saved settings and apply them to the objects 406 | readSettings(settingObjects) 407 | 408 | # Do a first update so that all the readings appear. 409 | update() 410 | # update every 10 seconds - temperature and humidity should move slowly so no need to demand 411 | # too much CPU time 412 | # 413 | 414 | #---------------------- support python 2 and 3 415 | GLib.timeout_add(10000, update) 416 | mainloop = GLib.MainLoop() 417 | logging.info ('Connected to dbus, and switching over to GLib.MainLoop() (= event based)') 418 | mainloop.run() 419 | #---------------------- 420 | 421 | 422 | -------------------------------------------------------------------------------- /gitHubInfo: -------------------------------------------------------------------------------- 1 | Rikkert-RS:latest 2 | -------------------------------------------------------------------------------- /i2c.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Thie file can be extended to add class drivers for additional devices as they are implemented and tested 4 | # https://github.com/Gozem/am2320/blob/master/am2320.py 5 | # file has been updated to catch and report errors (rather than raising and exception 6 | # use i2cdetect -y 1 on venus Rpi to check the device is found at address 5c 7 | 8 | import posix 9 | from fcntl import ioctl 10 | import time 11 | 12 | class AM2320: 13 | I2C_ADDR = 0x5c 14 | I2C_SLAVE = 0x0703 15 | 16 | def __init__(self, i2cbus = 1): 17 | self._i2cbus = i2cbus 18 | 19 | @staticmethod 20 | def _calc_crc16(data): 21 | crc = 0xFFFF 22 | for x in data: 23 | crc = crc ^ x 24 | for bit in range(0, 8): 25 | if (crc & 0x0001) == 0x0001: 26 | crc >>= 1 27 | crc ^= 0xA001 28 | else: 29 | crc >>= 1 30 | return crc 31 | 32 | @staticmethod 33 | def _combine_bytes(msb, lsb): 34 | return msb << 8 | lsb 35 | 36 | 37 | def readSensor(self): 38 | fd = posix.open("/dev/i2c-%d" % self._i2cbus, posix.O_RDWR) 39 | 40 | ioctl(fd, self.I2C_SLAVE, self.I2C_ADDR) 41 | 42 | # wake AM2320 up, goes to sleep to not warm up and affect the humidity sensor 43 | # This write will fail as AM2320 won't ACK this write 44 | try: 45 | posix.write(fd, b'\0x00') 46 | except: 47 | pass 48 | time.sleep(0.001) #Wait at least 0.8ms, at most 3ms 49 | 50 | # write at addr 0x03, start reg = 0x00, num regs = 0x04 */ 51 | try: 52 | posix.write(fd, b'\x03\x00\x04') 53 | except: 54 | posix.close(fd) 55 | return (0,0,1,"Device did not acknowledge request") 56 | time.sleep(0.0016) #Wait at least 1.5ms for result 57 | 58 | # Read out 8 bytes of result data 59 | # Byte 0: Should be Modbus function code 0x03 60 | # Byte 1: Should be number of registers to read (0x04) 61 | # Byte 2: Humidity msb 62 | # Byte 3: Humidity lsb 63 | # Byte 4: Temperature msb 64 | # Byte 5: Temperature lsb 65 | # Byte 6: CRC lsb byte 66 | # Byte 7: CRC msb byte 67 | data = bytearray(posix.read(fd, 8)) 68 | posix.close(fd) 69 | 70 | # Check data[0] and data[1] 71 | if data[0] != 0x03 or data[1] != 0x04: 72 | return (0,0,4,"First two read bytes are a mismatch") 73 | # raise Exception("First two read bytes are a mismatch") 74 | 75 | # CRC check 76 | if self._calc_crc16(data[0:6]) != self._combine_bytes(data[7], data[6]): 77 | return (0,0,4,"CRC failed") 78 | # raise Exception("CRC failed") 79 | 80 | # Temperature resolution is 16Bit, 81 | # temperature highest bit (Bit15) is equal to 1 indicates a 82 | # negative temperature, the temperature highest bit (Bit15) 83 | # is equal to 0 indicates a positive temperature; 84 | # temperature in addition to the most significant bit (Bit14 ~ Bit0) 85 | # indicates the temperature sensor string value. 86 | # Temperature sensor value is a string of 10 times the 87 | # actual temperature value. 88 | temp = self._combine_bytes(data[4], data[5]) 89 | if temp & 0x8000: 90 | temp = -(temp & 0x7FFF) 91 | temp /= 10.0 92 | 93 | humi = self._combine_bytes(data[2], data[3]) / 10.0 94 | 95 | return (temp, humi, 0,'') 96 | 97 | #am2320 = AM2320(1) 98 | #(t,h) = am2320.readSensor() 99 | #print 'temperature', t 100 | #print 'humidiy', h, ' %' 101 | -------------------------------------------------------------------------------- /i2c.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/i2c.pyc -------------------------------------------------------------------------------- /raspberryPiOnly: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/raspberryPiOnly -------------------------------------------------------------------------------- /screenshots/PackageManagerAddCustomPackage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/screenshots/PackageManagerAddCustomPackage.png -------------------------------------------------------------------------------- /screenshots/PackageManagerAddPackage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/screenshots/PackageManagerAddPackage.png -------------------------------------------------------------------------------- /screenshots/PackageManagerInstallAktivPackage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/screenshots/PackageManagerInstallAktivPackage.png -------------------------------------------------------------------------------- /screenshots/PackageManagerMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/screenshots/PackageManagerMenu.png -------------------------------------------------------------------------------- /screenshots/TempsInMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/screenshots/TempsInMenu.png -------------------------------------------------------------------------------- /service/log/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec 2>&1 3 | exec multilog t s99999 n8 /var/log/VenusOS-TemperatureService 4 | -------------------------------------------------------------------------------- /service/log/supervise/lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/service/log/supervise/lock -------------------------------------------------------------------------------- /service/log/supervise/status: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/service/log/supervise/status -------------------------------------------------------------------------------- /service/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec 2>&1 3 | exec softlimit -d 100000000 -s 1000000 -a 100000000 /data/VenusOS-TemperatureService/dbus-i2c.py 4 | -------------------------------------------------------------------------------- /service/supervise/lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/service/supervise/lock -------------------------------------------------------------------------------- /service/supervise/status: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rikkert-RS/VenusOS-TemperatureService/2982702844d7182e864f7279a71818a97ca533df/service/supervise/status -------------------------------------------------------------------------------- /setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #### add the following lines to the package's setup script 4 | 5 | #### following line incorporates helper resources into this script 6 | source "/data/SetupHelper/HelperResources/IncludeHelpers" 7 | #### end of lines to include helper resources 8 | # install TemperatureService for Victron Venus OS on Raspberry Pi 9 | 10 | overlayFile="/u-boot/overlays/w1-gpio.dtbo" 11 | configFile="/u-boot/config.txt" 12 | 13 | 14 | packageLogFile="/var/log/VenusOS-TemperatureService/current" 15 | 16 | 17 | 18 | 19 | #### running manually and OK to proceed - prompt for input 20 | if [ $scriptAction == 'NONE' ] ; then 21 | # display innitial message 22 | echo 23 | echo "This package brings the RPI's processor internal temperature to the GUI and VRM" 24 | 25 | standardActionPrompt 26 | fi 27 | 28 | #### install code goes here 29 | if [ $scriptAction == 'INSTALL' ] ; then 30 | 31 | logMessage "++ Installing VenusOS Temperature Service" 32 | 33 | installService $packageName 34 | 35 | # install DT overlay to for 1-Wire 36 | updateActiveFile "$overlayFile" 37 | 38 | if [ $(grep -c "w1-gpio" "$configFile") == 0 ]; then 39 | logMessage "activating 1-Wire overlay" 40 | echo "#### Change 1-Wire Temperatursensor GPIO" >> "$configFile" 41 | echo "dtoverlay=w1-gpio,gpiopin=26" >> "$configFile" 42 | echo "#### end change 1-Wire GPIO" >> "$configFile" 43 | filesUpdated=true 44 | fi 45 | 46 | fi 47 | 48 | #### uninstalling - check scriptAction again 49 | # if an install step failed package needs to be removed 50 | if [ $scriptAction == 'UNINSTALL' ] ; then 51 | logMessage "++ Uninstalling VenusOS Temperature Service" 52 | 53 | removeService $packageName 54 | 55 | restoreActiveFile "$overlayFile" 56 | 57 | # remove mods from configFile - do not use restore in case other mods were made manually 58 | if [ -f "$configFile" ]; then 59 | if [ $(grep -c "#### Change 1-Wire Temperatursensor GPIO" "$configFile") != 0 ]; then 60 | sed -i -e '/#### Change 1-Wire Temperatursensor GPIO/,/#### end change 1-Wire GPIO/d' "$configFile" 61 | filesUpdated=true 62 | fi 63 | fi 64 | # remove for older Verison 65 | if [ -f "$configFile" ]; then 66 | if [ $(grep -c "#### Change 1-Wire Temperatursensor on Pin4" "$configFile") != 0 ]; then 67 | sed -i -e '/#### Change 1-Wire Temperatursensor on Pin4/,/#### end change 1-Wire Pin4/d' "$configFile" 68 | filesUpdated=true 69 | fi 70 | fi 71 | # remove for older Verison 72 | if [ -f "$configFile" ]; then 73 | if [ $(grep -c "#### Change 1-Wire Temperatursensor on Pin26" "$configFile") != 0 ]; then 74 | sed -i -e '/#### Change 1-Wire Temperatursensor on Pin26/,/#### end change 1-Wire Pin26/d' "$configFile" 75 | filesUpdated=true 76 | fi 77 | fi 78 | fi 79 | 80 | if $filesUpdated ; then 81 | rebootNeeded=true 82 | fi 83 | 84 | 85 | # thats all folks - SCRIPT EXITS INSIDE THE FUNCTION 86 | endScript 87 | -------------------------------------------------------------------------------- /tests/c2.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | if [ ! -e /dev/i2c-* ]; then 4 | svc -d /service/dbus-i2c 5 | exit 6 | else 7 | echo "device driver found" 8 | fi 9 | 10 | -------------------------------------------------------------------------------- /tests/check-i2c.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | if ! pgrep -f "dbus-i2c.py" >/dev/null; then 4 | echo "process not found" 5 | else 6 | echo "process running" 7 | fi 8 | -------------------------------------------------------------------------------- /version: -------------------------------------------------------------------------------- 1 | v0.53 2 | --------------------------------------------------------------------------------