Closed aaronwmorris closed 1 year ago
@pawel-soja Can you please check?
@aaronwmorris Can you share how we can reproduce this issue exactly step by step?
@aaronwmorris do you have any logs? Have you recompiled all dependent libraries (e.g. indi-3rdparty)? Please provide additional information.
I cannot see indi beeing tagged at 1.9.9 yet 1.9.8 seems to work (with the simple test we've got atm) https://github.com/indilib/pyindi-client/actions/runs/3238312112/jobs/5306396117 building & testing against the current master atm https://github.com/indilib/pyindi-client/actions/runs/3544738039
@aaronwmorris what exactly caused the segfault, please add a test for it or at least an instrution on how to reproduce it
BTW: it might be a good idea to create more tests to cover more area!
The indi Ubuntu PPA repo has already released packages with the 1.9.9 release. I have also tested by compiling from source.
I finally had some time tonight to write some basic code and there seems to be a problem with setting properties. None of the current script examples that set properties in the repo are working.
If you already have pyindi-client installed, you will have to run the following to ensure you get the latest version from git.
pip3 install --no-binary :all: --upgrade 'git+https://github.com/indilib/pyindi-client.git@ffd939b#egg=pyindi-client'
Attached is an example script that just sets some simple properties with the CCD Simulator. In my indi-allsky project, I get segfaults or recursion errors, but the code for setting properties is more complex than my example below.
Anytime a property is changed, I receive an exception like the following.
2022-11-25 21:38:51,893 [INFO] MainProcess __init__() #36: INDI version: 1.9.9
2022-11-25 21:38:51,893 [INFO] MainProcess <module>() #81: Connecting to indiserver
INDI::BaseClient::connectServer: creating new connection...
2022-11-25 21:38:51,895 [INFO] MainProcess <module>() #94: Connecting to CCD Simulator
2022-11-25 21:38:51,896 [INFO] MainProcess newDevice() #40: new device CCD Simulator
2022-11-25 21:38:51,896 [INFO] MainProcess newDevice() #40: new device CCD Simulator
2022-11-25 21:38:51,896 [INFO] MainProcess newDevice() #40: new device Telescope Simulator
2022-11-25 21:38:51,897 [INFO] MainProcess newDevice() #40: new device Telescope Simulator
2022-11-25 21:38:52,397 [INFO] MainProcess <module>() #100: Get CONNECTION control
Traceback (most recent call last):
File "/home/aaron/git/indi-allsky/./testing/indi_basic.py", line 107, in <module>
indiclient.sendNewSwitch(connection)
File "/home/aaron/git/indi-allsky/virtualenv/indi-allsky/lib/python3.9/site-packages/PyIndi.py", line 912, in sendNewSwitch
return _PyIndi.BaseClient_sendNewSwitch(self, pp)
TypeError: in method 'BaseClient_sendNewSwitch', argument 2 of type 'INDI::PropertyView< ISwitch > *'
Test script:
#!/usr/bin/env python3
import PyIndi
import time
import sys
import logging
CCD = "CCD Simulator"
INDI_SERVER = "localhost"
INDI_PORT = 7624
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
LOG_FORMATTER_STREAM = logging.Formatter('%(asctime)s [%(levelname)s] %(processName)s %(funcName)s() #%(lineno)d: %(message)s')
LOG_HANDLER_STREAM = logging.StreamHandler()
LOG_HANDLER_STREAM.setFormatter(LOG_FORMATTER_STREAM)
logger.addHandler(LOG_HANDLER_STREAM)
class IndiClient(PyIndi.BaseClient):
def __init__(self):
super(IndiClient, self).__init__()
pyindi_version = '.'.join((
str(getattr(PyIndi, 'INDI_VERSION_MAJOR', -1)),
str(getattr(PyIndi, 'INDI_VERSION_MINOR', -1)),
str(getattr(PyIndi, 'INDI_VERSION_RELEASE', -1)),
))
logger.info("INDI version: %s", pyindi_version)
def newDevice(self, d):
logger.info("new device %s", d.getDeviceName())
def removeDevice(self, d):
logger.info("removed device %s", d.getDeviceName())
def newProperty(self, p):
pass
def removeProperty(self, p):
pass
def newBLOB(self, bp):
logger.info("new BLOB %s", bp.name)
def newSwitch(self, svp):
pass
def newNumber(self, nvp):
pass
def newText(self, tvp):
pass
def newLight(self, lvp):
pass
def newMessage(self, d, m):
pass
def serverConnected(self):
pass
def serverDisconnected(self, code):
pass
# connect to the server
indiclient = IndiClient()
indiclient.setServer(INDI_SERVER, INDI_PORT)
logger.info("Connecting to indiserver")
if not (indiclient.connectServer()):
logger.error(
"No indiserver running on %s:%d",
indiclient.getHost(),
indiclient.getPort()
)
sys.exit(1)
### Connect the CCD
device_ccd = None
while not device_ccd:
logger.info("Connecting to %s", CCD)
device_ccd = indiclient.getDevice(CCD)
time.sleep(0.5)
connection = None
while not connection:
logger.info("Get CONNECTION control")
connection = device_ccd.getSwitch("CONNECTION")
time.sleep(0.5)
if not device_ccd.isConnected():
connection[0].setState(PyIndi.ISS_ON) # CONNECT
connection[1].setState(PyIndi.ISS_OFF) # DISCONNECT
indiclient.sendNewSwitch(connection)
while not device_ccd.isConnected():
logger.warning('Waiting on ccd connection')
time.sleep(0.5)
logger.info("ccd connected")
### Number control test
equatorial_pe = None
while not equatorial_pe:
logger.info("Get EQUITORIAL_PE control (number)")
equatorial_pe = device_ccd.getNumber("EQUATORIAL_PE")
time.sleep(0.5)
logger.info("Set EQUATORIAL_PE to M13")
equatorial_pe[0].value = 16.7175 # RA_PE
equatorial_pe[1].value = 36.4233 # DEC_PE
indiclient.sendNewNumber(equatorial_pe)
### Text control test
ccd_directory_location = None
while not ccd_directory_location:
logger.info("Get CCD_DIRECTORY_LOCATION control (text)")
ccd_directory_location = device_ccd.getText("CCD_DIRECTORY_LOCATION")
time.sleep(0.5)
logger.info("Set CCD_DIRECTORY_LOCATION to /tmp")
ccd_directory_location[0].text = "/tmp" # LOCATION
indiclient.sendNewText(ccd_directory_location)
### Switch control test
simulate_bayer = None
while not simulate_bayer:
logger.info("Get SIMULATE_BAYER control (switch)")
simulate_bayer = device_ccd.getSwitch("SIMULATE_BAYER")
time.sleep(0.5)
logger.info("Set SIMULATE_BAYER to Enable")
simulate_bayer[0].setState(PyIndi.ISS_ON) # INDI_ENABLED
simulate_bayer[1].setState(PyIndi.ISS_OFF) # INDI_DISABLED
indiclient.sendNewSwitch(simulate_bayer)
Fantastic! Thank you very much for the example. I'll take care of this problem.
The problem is with the implicit conversion between types, which is natural and default in C++.
I will add additional constructors to INDI Core
to help with the conversion. In addition, a few things will need to be removed from the indiclientpython.i
file.
@knro It will be easy for me to make changes after approval: https://github.com/indilib/indi/pull/1767
Attached is an example script that just sets some simple properties with the CCD Simulator. In my indi-allsky project, I get segfaults or recursion errors, but the code for setting properties is more complex than my example below.
I didn't catch the segfaults.
I explain where the identified errors came from:
Inheriting from BaseClient which inherits BaseMediator, virtual methods had to be implemented.
def newDevice(self, d):
pass
def removeDevice(self, d):
pass
def newProperty(self, p):
pass
def removeProperty(self, p):
pass
def newBLOB(self, bp):
pass
def newSwitch(self, svp):
pass
def newNumber(self, nvp):
pass
def newText(self, tvp):
pass
def newLight(self, lvp):
pass
def newMessage(self, d, m):
pass
def serverConnected(self):
pass
def serverDisconnected(self, code):
pass
The problem started when a new virtual method was added in version 1.9.9
:
/** @brief Emmited when a new property value arrives from INDI server.
* @param property Property container.
*/
virtual void updateProperty(INDI::Property property);
The method was not implemented on the Python side and Swig generated a function that calls itself. However, the new library does not require virtual functions to be implemented as it implements empty functions by default.
To solve the problem, and not have to implement all functions if not needed, you should also mark the BaseMediator as (similar to BaseClient):
%feature("director") BaseMediator;
I thought there was a problem with assigning a PropertyXXX
value type to a Property
type, which shouldn't be because PropertyXXX
inherits from Property
.
The culprit of this problem is the extra lines: https://github.com/indilib/pyindi-client/blob/ffd939bebabdb5423cd1666f84288eafcb0996ff/indiclientpython.i#L222-L231
After removing them, the problem disappears.
I guess where they came from, in version 1.9.8
(basedevice.h):
/** @return Return vector number property given its name */
INDI::PropertyView<INumber> *getNumber(const char *name) const;
/** @return Return vector text property given its name */
INDI::PropertyView<IText> *getText(const char *name) const;
/** @return Return vector switch property given its name */
INDI::PropertyView<ISwitch> *getSwitch(const char *name) const;
/** @return Return vector light property given its name */
INDI::PropertyView<ILight> *getLight(const char *name) const;
/** @return Return vector BLOB property given its name */
INDI::PropertyView<IBLOB> *getBLOB(const char *name) const;
For version 1.9.9
low-level magic types are slowly disappearing (basedevice.h):
/** @return Return vector number property given its name */
INDI::PropertyNumber getNumber(const char *name) const;
/** @return Return vector text property given its name */
INDI::PropertyText getText(const char *name) const;
/** @return Return vector switch property given its name */
INDI::PropertySwitch getSwitch(const char *name) const;
/** @return Return vector light property given its name */
INDI::PropertyLight getLight(const char *name) const;
/** @return Return vector BLOB property given its name */
INDI::PropertyBlob getBLOB(const char *name) const;
There are still places where the previous types are behind, but I will try to use the new ones as soon as possible and add the appropriate constructors to the 1.9.9
version.
Soon I will upload appropriate pull requests to both repositories, I am currently testing if everything is ok.
I have tested the script above with the changes you implemented and the [simple] script works now.
However, I am still receiving a segfault with my more complex method of setting properties. I will upload a new example to demonstrate the segfault.
This is a more complex method of setting properties that allows setting property values by names instead of just manually setting the indexes. I left the unneeded methods in for testing with older versions of indi.
This is the segfault I receive:
$ ./indi_complex.py
2022-11-30 21:48:11,660 [INFO] MainProcess __init__() #75: creating an instance of IndiClient
2022-11-30 21:48:11,661 [INFO] MainProcess <module>() #288: Connecting to indiserver
INDI::BaseClient::connectServer: creating new connection...
2022-11-30 21:48:11,661 [INFO] MainProcess serverConnected() #121: Server connected (localhost:7624)
2022-11-30 21:48:11,662 [INFO] MainProcess newDevice() #79: new device CCD Simulator
2022-11-30 21:48:11,663 [INFO] MainProcess newDevice() #79: new device CCD Simulator
2022-11-30 21:48:11,664 [INFO] MainProcess newDevice() #79: new device Telescope Simulator
2022-11-30 21:48:11,665 [INFO] MainProcess newDevice() #79: new device Telescope Simulator
2022-11-30 21:48:19,670 [INFO] MainProcess findCcds() #144: Found device CCD Simulator
2022-11-30 21:48:19,671 [INFO] MainProcess findCcds() #149: Detected ccd
2022-11-30 21:48:19,672 [INFO] MainProcess findCcds() #149: Detected guider
2022-11-30 21:48:19,672 [INFO] MainProcess findCcds() #149: Detected filter
2022-11-30 21:48:19,673 [INFO] MainProcess findCcds() #144: Found device Telescope Simulator
2022-11-30 21:48:19,673 [INFO] MainProcess findCcds() #149: Detected telescope
2022-11-30 21:48:19,674 [INFO] MainProcess findCcds() #149: Detected guider
2022-11-30 21:48:19,675 [INFO] MainProcess <module>() #306: Found 1 CCDs
2022-11-30 21:48:19,675 [WARNING] MainProcess <module>() #309: Connecting to device CCD Simulator
2022-11-30 21:48:19,675 [INFO] MainProcess configureDevice() #159: Setting switch SIMULATE_BAYER
Segmentation fault
#!/usr/bin/env python3
import sys
import logging
import time
from collections import OrderedDict
import ctypes
import PyIndi
INDI_SERVER = 'localhost'
INDI_PORT = 7624
INDI_CONFIG = OrderedDict({
"SWITCHES" : {
"SIMULATE_BAYER" : {
"on" : ["INDI_ENABLED"],
"off" : ["INDI_DISABLED"],
},
},
"PROPERTIES" : {
"EQUATORIAL_PE" : {
"RA_PE" : 16.7175,
"DEC_PE" : 36.4233
},
},
"TEXT" : {
"CCD_DIRECTORY_LOCATION" : {
"LOCATION" : "/tmp",
},
},
})
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
LOG_FORMATTER_STREAM = logging.Formatter('%(asctime)s [%(levelname)s] %(processName)s %(funcName)s() #%(lineno)d: %(message)s')
LOG_HANDLER_STREAM = logging.StreamHandler()
LOG_HANDLER_STREAM.setFormatter(LOG_FORMATTER_STREAM)
logger.addHandler(LOG_HANDLER_STREAM)
class IndiClient(PyIndi.BaseClient):
__state_to_str = {
PyIndi.IPS_IDLE : 'IDLE',
PyIndi.IPS_OK : 'OK',
PyIndi.IPS_BUSY : 'BUSY',
PyIndi.IPS_ALERT : 'ALERT',
}
__indi_interfaces = {
PyIndi.BaseDevice.GENERAL_INTERFACE : 'general',
PyIndi.BaseDevice.TELESCOPE_INTERFACE : 'telescope',
PyIndi.BaseDevice.CCD_INTERFACE : 'ccd',
PyIndi.BaseDevice.GUIDER_INTERFACE : 'guider',
PyIndi.BaseDevice.FOCUSER_INTERFACE : 'focuser',
PyIndi.BaseDevice.FILTER_INTERFACE : 'filter',
PyIndi.BaseDevice.DOME_INTERFACE : 'dome',
PyIndi.BaseDevice.GPS_INTERFACE : 'gps',
PyIndi.BaseDevice.WEATHER_INTERFACE : 'weather',
PyIndi.BaseDevice.AO_INTERFACE : 'ao',
PyIndi.BaseDevice.DUSTCAP_INTERFACE : 'dustcap',
PyIndi.BaseDevice.LIGHTBOX_INTERFACE : 'lightbox',
PyIndi.BaseDevice.DETECTOR_INTERFACE : 'detector',
PyIndi.BaseDevice.ROTATOR_INTERFACE : 'rotator',
PyIndi.BaseDevice.AUX_INTERFACE : 'aux',
}
def __init__(self):
super(IndiClient, self).__init__()
self._timeout = 60.0
logger.info('creating an instance of IndiClient')
def newDevice(self, d):
logger.info("new device %s", d.getDeviceName())
def removeDevice(self, d):
logger.info("remove device %s", d.getDeviceName())
def newProperty(self, p):
#logger.info("new property %s for device %s", p.getName(), p.getDeviceName())
pass
def removeProperty(self, p):
logger.info("remove property %s for device %s", p.getName(), p.getDeviceName())
def newBLOB(self, bp):
logger.info("new BLOB %s", bp.name)
#start = time.time()
### get image data
bp.getblobdata()
#elapsed_s = time.time() - start
#logger.info('Blob downloaded in %0.4f s', elapsed_s)
def newSwitch(self, svp):
logger.info("new Switch %s for device %s", svp.name, svp.device)
def newNumber(self, nvp):
#logger.info("new Number %s for device %s", nvp.name, nvp.device)
pass
def newText(self, tvp):
logger.info("new Text %s for device %s", tvp.name, tvp.device)
def newLight(self, lvp):
logger.info("new Light %s for device %s", lvp.name, lvp.device)
def newMessage(self, d, m):
logger.info("new Message %s", d.messageQueue(m))
def serverConnected(self):
logger.info("Server connected (%s:%d)", self.getHost(), self.getPort())
def serverDisconnected(self, code):
logger.info("Server disconnected (exit code = %d, %s, %d", code, str(self.getHost()), self.getPort())
def findDeviceInterfaces(self, device):
interface = device.getDriverInterface()
if type(interface) is int:
device_interfaces = interface
else:
interface.acquire()
device_interfaces = int(ctypes.cast(interface.__int__(), ctypes.POINTER(ctypes.c_uint16)).contents.value)
interface.disown()
return device_interfaces
def findCcds(self):
ccd_list = list()
for device in self.getDevices():
logger.info('Found device %s', device.getDeviceName())
device_interfaces = self.findDeviceInterfaces(device)
for k, v in self.__indi_interfaces.items():
if device_interfaces & k:
logger.info(' Detected %s', v)
if k == PyIndi.BaseDevice.CCD_INTERFACE:
ccd_list.append(device)
return ccd_list
def configureDevice(self, device, indi_config):
### Configure Device Switches
for k, v in indi_config.get('SWITCHES', {}).items():
logger.info('Setting switch %s', k)
self.set_switch(device, k, on_switches=v.get('on', []), off_switches=v.get('off', []))
### Configure Device Properties
for k, v in indi_config.get('PROPERTIES', {}).items():
logger.info('Setting property (number) %s', k)
self.set_number(device, k, v)
### Configure Device Text
for k, v in indi_config.get('TEXT', {}).items():
logger.info('Setting property (text) %s', k)
self.set_text(device, k, v)
# Sleep after configuration
time.sleep(1.0)
def set_number(self, device, name, values, sync=True, timeout=None):
#logger.info('Name: %s, values: %s', name, str(values))
c = self.get_control(device, name, 'number')
for control_name, index in self.__map_indexes(c, values.keys()).items():
c[index].value = values[control_name]
self.sendNewNumber(c)
if sync:
self.__wait_for_ctl_statuses(c, timeout=timeout)
return c
def set_switch(self, device, name, on_switches=[], off_switches=[], sync=True, timeout=None):
c = self.get_control(device, name, 'switch')
is_exclusive = c.getRule() == PyIndi.ISR_ATMOST1 or c.getRule() == PyIndi.ISR_1OFMANY
if is_exclusive :
on_switches = on_switches[0:1]
off_switches = [s.name for s in c if s.name not in on_switches]
for index in range(0, len(c)):
current_state = c[index].getState()
new_state = current_state
if c[index].name in on_switches:
new_state = PyIndi.ISS_ON
elif is_exclusive or c[index].name in off_switches:
new_state = PyIndi.ISS_OFF
c[index].setState(new_state)
self.sendNewSwitch(c)
return c
def set_text(self, device, control_name, values, sync=True, timeout=None):
c = self.get_control(device, control_name, 'text')
for control_name, index in self.__map_indexes(c, values.keys()).items():
c[index].text = values[control_name]
self.sendNewText(c)
if sync:
self.__wait_for_ctl_statuses(c, timeout=timeout)
return c
def get_control(self, device, name, ctl_type, timeout=None):
if timeout is None:
timeout = self._timeout
ctl = None
attr = {
'number' : 'getNumber',
'switch' : 'getSwitch',
'text' : 'getText',
'light' : 'getLight',
'blob' : 'getBLOB'
}[ctl_type]
started = time.time()
while not ctl:
ctl = getattr(device, attr)(name)
if not ctl and 0 < timeout < time.time() - started:
raise TimeOutException('Timeout finding control {0}'.format(name))
time.sleep(0.1)
return ctl
def __map_indexes(self, ctl, values):
result = {}
for i, c in enumerate(ctl):
#logger.info('Value name: %s', c.name) # useful to find value names
if c.name in values:
result[c.name] = i
return result
def __wait_for_ctl_statuses(self, ctl, statuses=[PyIndi.IPS_OK, PyIndi.IPS_IDLE], timeout=None):
started = time.time()
if timeout is None:
timeout = self._timeout
while ctl.getState() not in statuses:
#logger.info('%s/%s/%s: %s', ctl.getDeviceName(), ctl.getGroupName(), ctl.getName(), self.__state_to_str[ctl.getState()])
if ctl.getState() == PyIndi.IPS_ALERT and 0.5 > time.time() - started:
raise RuntimeError('Error while changing property {0}'.format(ctl.getName()))
elapsed = time.time() - started
if 0 < timeout < elapsed:
raise TimeOutException('Timeout error while changing property {0}: elapsed={1}, timeout={2}, status={3}'.format(ctl.getName(), elapsed, timeout, self.__state_to_str[ctl.getState()] ))
time.sleep(0.05)
class TimeOutException(Exception):
pass
# instantiate the client
indiclient = IndiClient()
# set indi server localhost and port
indiclient.setServer(INDI_SERVER, INDI_PORT)
logger.info("Connecting to indiserver")
if not indiclient.connectServer():
logger.error("No indiserver running on %s:%d - Try to run", indiclient.getHost(), indiclient.getPort())
logger.error(" indiserver indi_simulator_telescope indi_simulator_ccd")
sys.exit(1)
# give devices a chance to register
time.sleep(8)
ccd_list = indiclient.findCcds()
if len(ccd_list) == 0:
logger.error('No CCDs detected')
time.sleep(1)
sys.exit(1)
logger.info('Found %d CCDs', len(ccd_list))
ccdDevice = ccd_list[0]
logger.warning('Connecting to device %s', ccdDevice.getDeviceName())
indiclient.connectDevice(ccdDevice.getDeviceName())
indiclient.configureDevice(ccdDevice, INDI_CONFIG)
Okay I have it.
off_switches = [s.name for s in c if s.name not in on_switches]
When items with a loop after any object, only the __getitem__
method is used. The __len__
function is not performed. In order for the loop to end at the right time, the __getitem__
function must quit the exception.
I added the appropriate fixes to https://github.com/indilib/pyindi-client/pull/27
That is awesome! You are killing it. :-) I tested the changes and it appears to be working.
Final question: With these changes to pyindi-client, will it be compatible with older versions of indi or will it require 1.9.9?
It should be backwards compatible, although I haven't tested all versions.
I recommend using getters and setters, additionally note that there are built-in functions that return string as state or rule.
#!/usr/bin/env python3
import PyIndi
prop = PyIndi.PropertySwitch(2)
# setters
prop.setDeviceName("Property Device Name")
prop.setName("Property Name")
prop.setLabel("Property Label")
prop.setGroupName("Property Group Name")
prop.setPermission(PyIndi.IP_RW)
prop.setTimeout(123)
prop.setState(PyIndi.IPS_BUSY)
prop.setTimestamp("1234")
prop.setRule(PyIndi.ISR_ATMOST1)
prop[0].setName("Widget Name 1")
prop[0].setLabel("Widget Label 1")
prop[0].setState(PyIndi.ISS_OFF)
prop[1].setName("Widget Name 2")
prop[1].setLabel("Widget Label 2")
prop[1].setState(PyIndi.ISS_ON)
# getters
print('---- property ----')
print(' getDeviceName:', prop.getDeviceName())
print(' getName:', prop.getName())
print(' getLabel:', prop.getLabel())
print(' getGroupName:', prop.getGroupName())
print(' getPermission:', prop.getPermission())
print('getPermissionAsString:', prop.getPermissionAsString())
print(' getTimeout:', prop.getTimeout())
print(' getTimestamp:', prop.getTimestamp())
print(' getRule:', prop.getRule())
print(' getRuleAsString:', prop.getRuleAsString())
for widget in prop:
print('')
print('---- widget ----')
print(' getName:', widget.getName())
print(' getLabel:', widget.getLabel())
print(' getState:', widget.getState())
print('getStateAsString:', widget.getStateAsString())
---- property ----
getDeviceName: Property Device Name
getName: Property Name
getLabel: Property Label
getGroupName: Property Group Name
getPermission: 2
getPermissionAsString: rw
getTimeout: 123.0
getTimestamp: 1234
getRule: 1
getRuleAsString: AtMostOne
---- widget ----
getName: Widget Name 1
getLabel: Widget Label 1
getState: 0
getStateAsString: Off
---- widget ----
getName: Widget Name 2
getLabel: Widget Label 2
getState: 1
getStateAsString: On
#!/usr/bin/env python3
import PyIndi
prop = PyIndi.Property(PyIndi.PropertySwitch(2))
print('Type:', prop.getTypeAsString())
print('Is light? ', PyIndi.PropertyLight(prop).isValid())
print('Is Switch?', PyIndi.PropertySwitch(prop).isValid())
print('Is Number?', PyIndi.PropertyNumber(prop).isValid())
switch = PyIndi.PropertySwitch(prop)
if switch:
print('if switch - true')
light = PyIndi.PropertyLight(prop)
if not light:
print('if not light - true')
Type: INDI_SWITCH
Is light? False
Is Switch? True
Is Number? False
if switch - true
if not light - true
Conversion can be useful when reading a given property through new methods in the mediator (now 3 methods are enough to handle all cases for a property). https://github.com/indilib/indi/blob/8d9ba364579804b0eebc5f3971844a34ac056d32/libs/indidevice/indibase.h#L105-L119
public:
/** @brief Emmited when a new property is created for an INDI driver.
* @param property Property container.
*/
virtual void newProperty(INDI::Property property);
/** @brief Emmited when a new property value arrives from INDI server.
* @param property Property container.
*/
virtual void updateProperty(INDI::Property property);
/** @brief Emmited when a property is deleted for an INDI driver.
* @param property Property container.
*/
virtual void removeProperty(INDI::Property property);
Very interesting information.
I had already converted some of the code to use getters and setters since direct access to some of the object properties no longer worked. Looks like I need to finish that work.
Looks like this fixes indi 1.9.9, unfortunately it is not backwards compatible with indi 1.9.8 or 1.9.7.
I will submit a PR to increment the version number of pyindi-client.
Some change in the indi core library is causing a segfault or other vague errors with pyindi-client (HEAD). I believe whatever is causing the segfault was added after Nov 6th.
pyindi-client is completely non-functional with indi 1.9.9