Skip to content

Commit

Permalink
Enabled all 6 relays for the Raspberry Pi platform
Browse files Browse the repository at this point in the history
  • Loading branch information
kwindrem committed Sep 26, 2021
1 parent 6a7c52c commit 09134bc
Show file tree
Hide file tree
Showing 17 changed files with 562 additions and 78 deletions.
Binary file modified .DS_Store
Binary file not shown.
Binary file modified FileSets/.DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions FileSets/fileList
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/opt/victronenergy/dbus-systemcalc-py/delegates/relaystate.py
17 changes: 5 additions & 12 deletions FileSets/gpio_list
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#### modified for use by the RpiGpio package
#### modified for use by the RpiGpio package on Raspberry PI platforms ONLY

# This is a list of gpio pins, set by the script /etc/rcS.d/S90gpio_pins.sh
# They are documented at: https://github.com/victronenergy/venus/wiki/bbb-gpio
Expand All @@ -12,21 +12,14 @@
# Relay 2 Pin 11 / GPIO 17
17 out relay_2

#### Relay 3 - 6 do NOT work on PI 4 and makes systemcalc crash!
#### This package includes mods to relaystate.py
#### However, PageSettingsRelay.qml needs to be updated for the additional relays
#### in order to control them manually from the GUI
#### many other modifications are needed to hook up other functions to anything but Relay 1
#### These modifications are NOT included in this package

# Relay 3 Pin 13 / GPIO 27
#27 out relay_3
27 out relay_3
# Relay 4 Pin 15 / GPIO 22
#22 out relay_4
22 out relay_4
# Relay 5 Pin 16 / GPIO 23
#23 out relay_5
23 out relay_5
# Relay 6 Pin 18 / GPIO 24
#24 out relay_6
24 out relay_6

# these have pull UPs
# Digital input 1 Pin 29 / GPIO 05
Expand Down
Binary file added FileSets/v2.40/.DS_Store
Binary file not shown.
107 changes: 107 additions & 0 deletions FileSets/v2.40/relaystate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import gobject
import logging
import os
import traceback
from glob import glob

# Victron packages
from ve_utils import exit_on_error

from delegates.base import SystemCalcDelegate

class RelayState(SystemCalcDelegate):
RELAY_GLOB = '/dev/gpio/relay_*'

def __init__(self):
SystemCalcDelegate.__init__(self)
self._relays = {}

def get_input(self):
return [
('com.victronenergy.settings', [
'/Settings/Relay/Function'])] # Managed by the gui

def get_settings(self):
return [
('/Relay/0/State', '/Settings/Relay/0/InitialState', 0, 0, 1),
('/Relay/1/State', '/Settings/Relay/1/InitialState', 0, 0, 1),
('/Relay/2/State', '/Settings/Relay/2/InitialState', 0, 0, 1),
('/Relay/3/State', '/Settings/Relay/3/InitialState', 0, 0, 1),
('/Relay/4/State', '/Settings/Relay/4/InitialState', 0, 0, 1),
('/Relay/5/State', '/Settings/Relay/5/InitialState', 0, 0, 1),
('/Relay/6/State', '/Settings/Relay/6/InitialState', 0, 0, 1)
]

@property
def relay_function(self):
return self._dbusmonitor.get_value('com.victronenergy.settings',
'/Settings/Relay/Function')

def set_sources(self, dbusmonitor, settings, dbusservice):
SystemCalcDelegate.set_sources(self, dbusmonitor, settings, dbusservice)
relays = sorted(glob(self.RELAY_GLOB))

if len(relays) == 0:
logging.info('No relays found')
return

self._relays.update({'/Relay/{}/State'.format(i): os.path.join(r, 'value') \
for i, r in enumerate(relays) })

gobject.idle_add(exit_on_error, self._init_relay_state)
for dbus_path in self._relays.iterkeys():
self._dbusservice.add_path(dbus_path, value=None, writeable=True,
onchangecallback=self._on_relay_state_changed)

logging.info('Relays found: {}'.format(', '.join(self._relays.values())))

def _init_relay_state(self):
if self.relay_function is None:
return True # Try again on the next idle event

for dbus_path, path in self._relays.iteritems():
if self.relay_function != 2 and dbus_path == '/Relay/0/State':
continue # Skip primary relay if function is not manual
state = self._settings[dbus_path]
self._dbusservice[dbus_path] = state
self.__on_relay_state_changed(dbus_path, state)

# Sync state back to dbus
self._update_relay_state()

# Watch changes and update dbus. Do we still need this?
gobject.timeout_add(5000, exit_on_error, self._update_relay_state)
return False

def _update_relay_state(self):
# @todo EV Do we still need this? Maybe only at startup?
for dbus_path, file_path in self._relays.items():
try:
with open(file_path, 'rt') as r:
state = int(r.read().strip())
self._dbusservice[dbus_path] = state
except (IOError, ValueError):
traceback.print_exc()
return True

def __on_relay_state_changed(self, dbus_path, state):
try:
path = self._relays[dbus_path]
with open(path, 'wt') as w:
w.write(str(state))
except IOError:
traceback.print_exc()
return False
return True

def _on_relay_state_changed(self, dbus_path, value):
try:
state = int(bool(value))
except ValueError:
traceback.print_exc()
return False
try:
return self.__on_relay_state_changed(dbus_path, state)
finally:
# Remember the state to restore after a restart
self._settings[dbus_path] = state
102 changes: 102 additions & 0 deletions FileSets/v2.40/relaystate.py.orig
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import gobject
import logging
import os
import traceback
from glob import glob

# Victron packages
from ve_utils import exit_on_error

from delegates.base import SystemCalcDelegate

class RelayState(SystemCalcDelegate):
RELAY_GLOB = '/dev/gpio/relay_*'

def __init__(self):
SystemCalcDelegate.__init__(self)
self._relays = {}

def get_input(self):
return [
('com.victronenergy.settings', [
'/Settings/Relay/Function'])] # Managed by the gui

def get_settings(self):
return [
('/Relay/0/State', '/Settings/Relay/0/InitialState', 0, 0, 1),
('/Relay/1/State', '/Settings/Relay/1/InitialState', 0, 0, 1)
]

@property
def relay_function(self):
return self._dbusmonitor.get_value('com.victronenergy.settings',
'/Settings/Relay/Function')

def set_sources(self, dbusmonitor, settings, dbusservice):
SystemCalcDelegate.set_sources(self, dbusmonitor, settings, dbusservice)
relays = sorted(glob(self.RELAY_GLOB))

if len(relays) == 0:
logging.info('No relays found')
return

self._relays.update({'/Relay/{}/State'.format(i): os.path.join(r, 'value') \
for i, r in enumerate(relays) })

gobject.idle_add(exit_on_error, self._init_relay_state)
for dbus_path in self._relays.iterkeys():
self._dbusservice.add_path(dbus_path, value=None, writeable=True,
onchangecallback=self._on_relay_state_changed)

logging.info('Relays found: {}'.format(', '.join(self._relays.values())))

def _init_relay_state(self):
if self.relay_function is None:
return True # Try again on the next idle event

for dbus_path, path in self._relays.iteritems():
if self.relay_function != 2 and dbus_path == '/Relay/0/State':
continue # Skip primary relay if function is not manual
state = self._settings[dbus_path]
self._dbusservice[dbus_path] = state
self.__on_relay_state_changed(dbus_path, state)

# Sync state back to dbus
self._update_relay_state()

# Watch changes and update dbus. Do we still need this?
gobject.timeout_add(5000, exit_on_error, self._update_relay_state)
return False

def _update_relay_state(self):
# @todo EV Do we still need this? Maybe only at startup?
for dbus_path, file_path in self._relays.items():
try:
with open(file_path, 'rt') as r:
state = int(r.read().strip())
self._dbusservice[dbus_path] = state
except (IOError, ValueError):
traceback.print_exc()
return True

def __on_relay_state_changed(self, dbus_path, state):
try:
path = self._relays[dbus_path]
with open(path, 'wt') as w:
w.write(str(state))
except IOError:
traceback.print_exc()
return False
return True

def _on_relay_state_changed(self, dbus_path, value):
try:
state = int(bool(value))
except ValueError:
traceback.print_exc()
return False
try:
return self.__on_relay_state_changed(dbus_path, state)
finally:
# Remember the state to restore after a restart
self._settings[dbus_path] = state
Binary file added FileSets/v2.65/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
#### This file has been automatically modified add relays 3-6
#### Search for MODIFIED to find changes

import gobject
import logging
import os
Expand All @@ -14,10 +11,6 @@

class RelayState(SystemCalcDelegate):
RELAY_GLOB = '/dev/gpio/relay_*'
FUNCTION_ALARM = 0
FUNCTION_MANUAL = 2
FUNCTION_BMS_STOPCHARGE = 4
FUNCTION_BMS_STOPDISCHARGE = 5

def __init__(self):
SystemCalcDelegate.__init__(self)
Expand All @@ -26,14 +19,12 @@ def __init__(self):
def get_input(self):
return [
('com.victronenergy.settings', [
'/Settings/Relay/Function',
'/Settings/Relay/1/Function'])] # Managed by the gui
'/Settings/Relay/Function'])] # Managed by the gui

#### MODIFIED - added relay 2 - 6
def get_settings(self):
return [
('/Relay/0/State', '/Settings/Relay/0/InitialState', 0, 0, 1),
('/Relay/1/State', '/Settings/Relay/1/InitialState', 0, 0, 1),
('/Relay/0/State', '/Settings/Relay/0/InitialState', 0, 0, 1),
('/Relay/1/State', '/Settings/Relay/1/InitialState', 0, 0, 1),
('/Relay/2/State', '/Settings/Relay/2/InitialState', 0, 0, 1),
('/Relay/3/State', '/Settings/Relay/3/InitialState', 0, 0, 1),
('/Relay/4/State', '/Settings/Relay/4/InitialState', 0, 0, 1),
Expand All @@ -46,11 +37,6 @@ def relay_function(self):
return self._dbusmonitor.get_value('com.victronenergy.settings',
'/Settings/Relay/Function')

@property
def relay1_function(self):
return self._dbusmonitor.get_value('com.victronenergy.settings',
'/Settings/Relay/1/Function')

def set_sources(self, dbusmonitor, settings, dbusservice):
SystemCalcDelegate.set_sources(self, dbusmonitor, settings, dbusservice)
relays = sorted(glob(self.RELAY_GLOB))
Expand All @@ -69,33 +55,20 @@ def set_sources(self, dbusmonitor, settings, dbusservice):

logging.info('Relays found: {}'.format(', '.join(self._relays.values())))

def set_relay(self, dbus_path, state):
self._dbusservice[dbus_path] = state
self.__on_relay_state_changed(dbus_path, state)

def set_function(self, func, state):
""" Find a relay bound to the relevant function, and set state. """
for p, r in ((self.relay_function, '/Relay/0/State'),
(self.relay1_function, '/Relay/1/State')):
if p == func and self._dbusservice[r] != state:
self.set_relay(r, state)

def _init_relay_state(self):
if self.relay_function is None:
return True # Try again on the next idle event

for dbus_path, path in self._relays.iteritems():
if dbus_path == '/Relay/0/State' and self.relay_function != self.FUNCTION_MANUAL:
if self.relay_function != 2 and dbus_path == '/Relay/0/State':
continue # Skip primary relay if function is not manual
if dbus_path == '/Relay/1/State' and self.relay1_function != self.FUNCTION_MANUAL:
continue # Skip secondary relay if function is not manual

try:
state = self._settings[dbus_path]
except KeyError:
pass
else:
self.set_relay(dbus_path, state)
self._dbusservice[dbus_path] = state
self.__on_relay_state_changed(dbus_path, state)

# Sync state back to dbus
self._update_relay_state()
Expand Down
Loading

0 comments on commit 09134bc

Please sign in to comment.