def writeGroupsToDali(self, dali): logger.info("Writing group stuff to DALI-device") # Remark: Non named groups from file will be left untouched nor will be # deleted from devices. for deviceShortAddr in self.data["devices"].keys(): logging.debug("Device %u: Query for groupmask" % (deviceShortAddr)) # Get group info may speedup setting things later on. grp = d.send(QueryGroupsZeroToSeven(deviceShortAddr)) grp2 = d.send(QueryGroupsEightToFifteen(deviceShortAddr)) groupMask = grp2.value.as_integer << 8 | grp.value.as_integer logging.debug("Device %u: Groupmask: 0x%x" % (deviceShortAddr, groupMask)) for groupId in range(16): currentlyMemberOfGroup = (groupMask & (1 << groupId)) != 0 memberOfGroup = groupId in self.data[ "groups"] and deviceShortAddr in self.data["groups"][ groupId] # logging.debug("Device %u / group %u: member: %r, newMember: %r"%(deviceShortAddr,groupId,currentlyMemberOfGroup,memberOfGroup)) if memberOfGroup != currentlyMemberOfGroup: logging.debug( "Device %u: Correcting group (%u) assignment" % (deviceShortAddr, groupId)) if memberOfGroup: dali.send(AddToGroup(Short(deviceShortAddr), groupId)) else: dali.send( RemoveFromGroup(Short(deviceShortAddr), groupId)) logger.info("Writing group stuff to DALI-device was successful")
def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the DALI Light platform.""" from dali.driver.hasseb import SyncHassebDALIUSBDriver from dali.address import Short from dali.command import YesNoResponse, Response import dali.gear.general as gear dali_driver = SyncHassebDALIUSBDriver() import threading lock = threading.RLock() lamps = [] for lamp in range(0,config[CONF_MAX_GEARS]): try: _LOGGER.debug("Searching for Gear on address <{}>".format(lamp)) r = dali_driver.send(gear.QueryControlGearPresent(Short(lamp))) if isinstance(r, YesNoResponse) and r.value: lamps.append(Short(lamp)) except Exception as e: #Not present _LOGGER.error("Error while QueryControlGearPresent: {}".format(e)) break add_devices([DALILight(dali_driver, lock, config[CONF_NAME], l) for l in lamps])
def __init__(self, driver, driver_lock, ballast): from dali.address import Short from dali.gear.general import QueryStatus from dali.gear.general import QueryStatusResponse from dali.gear.general import DTR0 from dali.gear.general import QueryPowerOnLevel from dali.gear.general import QueryLampPowerOn """Initialize a DALI Light.""" self._id = ballast['id'] self._name = ballast['name'] self._brightness = 0 self._state = False self.driver = driver self.driver_lock = driver_lock self.addr = Short(int(self._id)) with self.driver_lock: cmd = QueryPowerOnLevel(self.addr) r = self.driver.send(cmd) if r.value != None: self._brightness = to_hass_level(r.value.as_integer) with self.driver_lock: cmd = QueryLampPowerOn(self.addr) r = self.driver.send(cmd) if r.value != None: self._state = r.value
def writeScenesToDali(self, dali): for (sceneId, sceneContent) in self.data["scenes"].iteritems(): logging.debug("Working on Scene %u" % (sceneId)) for deviceShortAddr in self.data["devices"].keys(): sceneValue = None if deviceShortAddr in sceneContent: sceneValue = sceneContent[deviceShortAddr] elif "default" in sceneContent: sceneValue = sceneContent["default"] if sceneValue is not None: logging.debug("Device %u: Set scene level to %u" % (deviceShortAddr, sceneValue)) dali.send(DTR0(sceneValue)) dali.send(SetScene(deviceShortAddr, sceneId)) r = dali.send(QuerySceneLevel(deviceShortAddr, sceneId)) if r.value.as_integer != sceneValue: logging.error( "Device %u: Set scene level to %u FAILED (query retrieves: %u)" % (deviceShortAddr, sceneValue, r.value.as_integer)) else: logging.debug("Device %u: Remove from scene" % (deviceShortAddr)) dali.send(RemoveFromScene(Short(deviceShortAddr), sceneId))
def __init__(self, address, name=None, bus=None): if not isinstance(address, int) or address < 0 or address > 63: raise ValueError("address must be an integer in the range 0..63") self.address = address self._addressobj = Short(address) self.bus = None if bus: self.bind(bus)
def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the DALI Light platform.""" from dali.address import Short from dali.command import YesNoResponse, Response import dali.gear.general as gear from dali.driver.hasseb import SyncHassebDALIUSBDriverFactory from dali.driver.hasseb import SyncHassebDALIUSBDriver import threading dali_drivers = SyncHassebDALIUSBDriverFactory() for idx, dali_driver in enumerate(dali_drivers): _LOGGER.debug("Found DALI driver") lock = threading.RLock() driver_config = config[CONF_DRIVERS][idx] lamps = [] for lamp in range(0, driver_config[CONF_MAX_GEARS]): try: # @TODO initialize new gears _LOGGER.debug( "Searching for Gear on address <{}>".format(lamp)) r = dali_driver.send(gear.QueryControlGearPresent(Short(lamp))) if isinstance(r, YesNoResponse) and r.value: _LOGGER.debug("Found lamp!") lamps.append(Short(lamp)) except Exception as e: # This will often mean that the driver wasn't found _LOGGER.error( "Error while QueryControlGearPresent: {}".format(e)) _LOGGER.error("Hasseb DALI master not found") break add_devices([ DALILight(dali_driver, lock, driver_config[CONF_NAME], l, idx) for l in lamps ]) add_devices([ DALIBus(dali_driver, lock, driver_config[CONF_NAME], lamps, config[CONF_MAX_BUSES], idx) ])
def QueryDT1(d, addr): from dali.gear.emergency import QueryEmergencyFailureStatus from dali.gear.emergency import QueryEmergencyFeatures from dali.gear.emergency import QueryEmergencyMode from dali.gear.emergency import QueryEmergencyStatus d.send(EnableDeviceType(1)) r = d.send(QueryEmergencyMode(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(1)) r = d.send(QueryEmergencyFeatures(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(1)) r = d.send(QueryEmergencyFailureStatus(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(1)) r = d.send(QueryEmergencyStatus(Short(addr))) logging.info(" -- {0}".format(r))
def enter_interactive_mode(self): # First program a free short address and remember it if self.nextShortAddress in self.assignedAddresses: for i in xrange(63, -1, -1): if i not in self.assignedAddresses: self.nextShortAddress = i break self.ifc.send(ProgramShortAddress(self.nextShortAddress)) while True: print( "Enter number to assign to flashing ballast or press enter to flash again: " ) # Flash the ballast time.sleep(1) self.ifc.send(DAPC(Short(self.nextShortAddress), 0)) time.sleep(1) self.ifc.send(DAPC(Short(self.nextShortAddress), 254)) try: newAddress = int(raw_input()) except: continue if newAddress < 0 or newAddress >= 64: print("ERROR: Out of range") continue if newAddress in self.assignedAddresses: print("ERROR: Address already chosen") continue self.ifc.send(ProgramShortAddress(newAddress)) # It seems to be quite enough to set the address again. #self.ifc.send(DTR0(newAddress<<1 | 0x01)) #self.ifc.send(SetShortAddress(Short(self.nextShortAddress) )) self.assignedAddresses.append(newAddress) return newAddress
def __init__(self, address, randomAddress=None, deviceType=None, groups=None, bus=None): if not isinstance(address, int) or address < 0 or address > 63: print("Address must be an integer in the range 0..63") self.address = address self.address_obj = Short(address) self.bus = None if bus: self.bind(bus) self.randomAddress = randomAddress self.deviceType = deviceType self.groups = groups
def QueryDT6(d, addr): from dali.gear.led import QueryFeatures from dali.gear.led import QueryGearType from dali.gear.led import QueryOperatingMode from dali.gear.led import QueryFailureStatus from dali.gear.led import QueryFastFadeTime from dali.gear.led import QueryMinFastFadeTime from dali.gear.led import QueryDimmingCurve d.send(EnableDeviceType(6)) r = d.send(QueryFeatures(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(6)) r = d.send(QueryGearType(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(6)) r = d.send(QueryOperatingMode(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(6)) r = d.send(QueryFailureStatus(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(6)) r = d.send(QueryFastFadeTime(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(6)) r = d.send(QueryMinFastFadeTime(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(6)) r = d.send(QueryDimmingCurve(Short(addr))) logging.info(" -- {0}".format(r))
def test_construct_length_16(self): driver = UnipiDALIDriver() command = DAPC(Short(1), 2) self.assertEqual(driver.construct(command), (512, 514))
import signal import sys import time # setup console logging logger = logging.getLogger('UnipiDALIDriver') #logger.setLevel(logging.DEBUG) handler = logging.StreamHandler(sys.stdout) handler.setLevel(logging.DEBUG) handler.setFormatter( logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) # sync interface addr = Short(int(sys.argv[1])) # command to send #command = DAPC(addr, int(sys.argv[2])) #_test_sync(logger, command) command = QueryStatus(addr) _test_sync(logger, command) command = QueryDeviceType(addr) _test_sync(logger, command) #command = QueryLightSourceType(addr) #_test_sync(logger, command) command = QueryActualLevel(addr) _test_sync(logger, command) #command = RecallMaxLevel(addr) #command = RecallMinLevel(addr) command = Off(addr) _test_sync(logger, command)
#!/usr/bin/env python from dali.address import Broadcast from dali.address import Short from dali.gear.general import DAPC from dali.interface import DaliServer import sys if __name__ == "__main__": addr = Short(int(sys.argv[1])) if sys.argv[1] != "all" else Broadcast() level = int(sys.argv[2]) d = DaliServer("localhost", 55825) cmd = DAPC(addr, level) d.send(cmd)
from dali.address import Short from dali.gear.general import EnableDeviceType from dali.gear.general import QueryDeviceType from dali.gear.emergency import QueryEmergencyFailureStatus from dali.gear.emergency import QueryEmergencyFeatures from dali.gear.emergency import QueryEmergencyMode from dali.gear.emergency import QueryEmergencyStatus from dali.driver.launchpad_lw14 import LAUNCHPAD_LED_WARRIOR_14 import logging if __name__ == "__main__": log_format = '%(levelname)s: %(message)s' logging.basicConfig(format=log_format, level=logging.DEBUG) d = LAUNCHPAD_LED_WARRIOR_14(port='/dev/ttyACM0') for addr in range(0, 64): cmd = QueryDeviceType(Short(addr)) r = d.send(cmd) logging.info("[%d]: resp: %s" % (addr, r)) if r.value == 1: d.send(EnableDeviceType(1)) r = d.send(QueryEmergencyMode(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(1)) r = d.send(QueryEmergencyFeatures(Short(addr))) logging.info(" -- {0}".format(r)) d.send(EnableDeviceType(1)) r = d.send(QueryEmergencyFailureStatus(Short(addr)))
d.send(EnableDeviceType(6)) r = d.send(QueryDimmingCurve(Short(addr))) logging.info(" -- {0}".format(r)) def QueryDT8(d, addr): pass if __name__ == "__main__": log_format = '%(levelname)s: %(message)s' logging.basicConfig(format=log_format, level=logging.DEBUG) with DaliServer() as d: for addr in range(0, 64): cmd = QueryDeviceType(Short(addr)) r = d.send(cmd) logging.info("[%d]: resp: %s" % (addr, r)) if r.value is not None: if r.value.as_integer == 255: while True: cmd = QueryNextDeviceType(Short(addr)) r = d.send(cmd) if r.value is not None and r.value != 254: QueryGear(d, r.value.as_integer, addr) else: break else: QueryGear(d, r.value.as_integer, addr)
def Commissioning(available_addresses=None, readdress=False, dry_run=False): """Assign short addresses to control gear If available_addresses is passed, only the specified addresses will be assigned; otherwise all short addresses are considered to be available. if "readdress" is set, all existing short addresses will be cleared; otherwise, only control gear that is currently unaddressed will have short addresses assigned. If "dry_run" is set then no short addresses will actually be set. This can be useful for testing. """ if available_addresses is None: available_addresses = list(range(64)) else: available_addresses = list(available_addresses) if readdress: if dry_run: yield progress(message="dry_run is set: not deleting existing " "short addresses") else: yield DTR0(255) yield SetShortAddress(Broadcast()) else: # We need to know which short addresses are already in use for a in range(0, 64): if a in available_addresses: in_use = yield QueryControlGearPresent(Short(a)) if in_use.value: available_addresses.remove(a) yield progress(message=f"Available addresses: {available_addresses}") yield Terminate() yield Initialise(broadcast=True if readdress else False) finished = False # We loop here to cope with multiple devices picking the same # random search address; when we discover that, we # re-randomise and begin again. Devices that have already # received addresses are unaffected. while not finished: yield Randomise() # Randomise can take up to 100ms yield sleep(0.1) low = 0 high = 0xffffff while low is not None: yield progress(completed=low, size=high) low = yield from _find_next(low, high) if low == "clash": yield progress(message="Multiple ballasts picked the same " "random address; restarting") break if low is None: finished = True break yield progress(message=f"Ballast found at address {low:#x}") if available_addresses: new_addr = available_addresses.pop(0) if dry_run: yield progress(message="Not programming short address " f"{new_addr} because dry_run is set") else: yield progress( message=f"Programming short address {new_addr}") yield ProgramShortAddress(new_addr) r = yield VerifyShortAddress(new_addr) if r.value is not True: raise ProgramShortAddressFailure(new_addr) else: yield progress( message="Device found but no short addresses left") yield Withdraw() if low < high: low = low + 1 else: low = None finished = True yield Terminate() yield progress(message="Addressing complete")
def test_construct_length_16_config(self): driver = UnipiDALIDriver() command = Reset(Short(1)) self.assertEqual(driver.construct(command), (2560, 800))
async def main(args, loop): driver = drivers[args.driver] d = driver(args.device, loop=loop) if args.debug: d.bus_traffic.register(print_command_and_response) if not d.connect(): log.error("Unable to open device %s with %s driver", args.device, args.driver) d.disconnect() return await d.connected.wait() log.info("Connected to device %s with %s driver", args.device, args.driver) available_addresses = list(range(0, 64)) if args.mode != "readdress": # Work out which short addresses are in use for a in range(0, 64): in_use = await d.send(QueryControlGearPresent(Short(a))) if in_use.value: available_addresses.remove(a) log.info("Addresses available for allocation: %s", available_addresses) if args.mode == "readdress": if args.dry_run: log.info("Not deleting existing addresses because --dry-run") else: await d.send(DTR0(255)) await d.send(SetShortAddress(Broadcast())) await d.send(Terminate()) await d.send( Initialise(broadcast=True if args.mode == "readdress" else False)) await d.send(Randomise()) # Randomise can take up to 100ms await asyncio.sleep(0.1) low = 0 high = 0xffffff while low is not None: low = await find_next(d, low, high) if low is not None: if available_addresses: new_addr = available_addresses.pop(0) if args.dry_run: log.info( "Not programming short address %s because --dry-run", new_addr) else: log.info("Programming short address %s", new_addr) await d.send(ProgramShortAddress(new_addr)) r = await d.send(VerifyShortAddress(new_addr)) if r.value is not True: log.error("Device did not accept short address %s", new_addr) else: log.info("Device found but no short addresses remaining") await d.send(Withdraw()) low = low + 1 await d.send(Terminate()) log.info("Addressing complete") d.disconnect()