busylight icon indicating copy to clipboard operation
busylight copied to clipboard

Device based models / information

Open henryruhs opened this issue 1 year ago • 13 comments

It would improve the developer experience to have specific models for each device instead of generic ones. Using info['serial_number'] for example could throw a warning via the mypy type checker. I suggest to ban a key if there is no value present.

At this point I have to buy each device to make sure the code that I write is actual working. Wouldn't it be great the API tells me what the device supports.

Having a printed list of each device info in the docs would be a great addition too.

henryruhs avatar Oct 02 '22 22:10 henryruhs

I don't understand what you are asking for, could you be more specific please?

JnyJny avatar Oct 02 '22 23:10 JnyJny

Let me try to explain it with some pseudo code (be aware I wrote this as a prove of concept). There should be one LightInfoKey literal for each device.

from pydantic import BaseModel
from typing import Dict, Tuple, Union, Literal

LightInfoKey = Literal['vendor_id', 'product_id', 'serial_number']
LightInfo = Dict[LightInfoKey, Union[bytes, int, str, Tuple[int, int]]]

class LightDescription(BaseModel, LightInfo):
    light_id: int
    name: str
    info: LightInfo
    is_on: bool
    color: str
    rgb: Tuple[int, int, int]

#this should throw an typing error as path is not defined
#in case path does exist but is empty, I suggest to skip it in LightInfoKey
light.info['path']

#this is a valid access to the dict
light.info['vendor_id']

henryruhs avatar Oct 03 '22 08:10 henryruhs

How would you use this information?

JnyJny avatar Oct 03 '22 15:10 JnyJny

It helps me to integrate devices that I actual don't own.

henryruhs avatar Oct 03 '22 15:10 henryruhs

I don't mean to be obtuse, but isn't that the point of using a library like busylight? I've already done the work but you are unwilling or unable to use it? As far the the model you posted, that already exists to some degree in busylight.api.models (but will go away when I move busyserve out of the busylight-for-humans package, which is imminent).

I am still confused about how this information would be made available and how you would use it to "integrate" devices.

JnyJny avatar Oct 03 '22 15:10 JnyJny

I've already done the work but you are unwilling or unable to use it.

That is not the case, I properly use it in a way you never thought of. It's not fair to accuse me in that manner.

Example

Chroma Feedback provides filtering of it's consumer via ARGS.

program.add_argument('--compulab-fit-statusb-light-serial', action = 'append')

Each consumer provides a filtering method similar to this:

def filter_lights(lights : Any, light_serials : List[str]) -> Any:
	if light_serials:
		for light in copy.copy(lights):
			if light.info['serial_number'] not in light_serials:
				lights.remove(light)
	return lights

Not every device actual contains a info['serial_number'], so I usually fallback to it's .path.

def filter_lights(lights : Any, light_ids : List[str]) -> Any:
	if light_ids:
		for light in copy.copy(lights):
			if light.path not in light_ids:
				lights.remove(light)
	return lights

Developer are forced to own a device to integrate it properly. Like I said, a section in the docs for each device containing all information and properties would a helpfull addition or alternative.

henryruhs avatar Oct 03 '22 17:10 henryruhs

Perhaps that was unfair, but it motivated you to provide more useful information.

I have never guaranteed the contents of busylight.lights.Light.info, it's the bucket of data I receive from either hid.enumerate() or serial.tools.list_ports() and the only information I regularly consume out of that is vendor_id, product_id, and path. Yes, there are some exceptions to the rule: BlinkStick and Luxafor devices for instance. Unfortunately, the USB specification does not require vendors to populate all those fields with useful information (or even consistent information) so trying to provide a consistent API to that data is a losing battle.

I suppose I still don't understand the motivation behind the light filtering functions you've shared here and I don't understand yet how your LightDescription would be delivered to the developer other than "docs" and how they would help improve your filter functions.

JnyJny avatar Oct 03 '22 17:10 JnyJny

Not sure what to add to this conversation as you don't understand my intention to have a typesafe info. I close the issue.

henryruhs avatar Oct 03 '22 18:10 henryruhs

Asking questions is usually how I learn things. You have yet to clearly express your actual problem and what I could provide that would fix it. You've come closer with "type safe info" but does that mean a dictionary you can access without fear of a missing key or is this just to satisfy mypy?

JnyJny avatar Oct 03 '22 19:10 JnyJny

It's not to satisfy mypy - it's to prevent potential KeyValue exceptions and know what keys actual return a value without owning the device. Typing does improve the developer experience and can prevent falsy usage.

Example

from typing import Dict, Literal

LightInfoKey = Literal['vendor_id', 'product_id', 'serial_number']
LightInfo = Dict[LightInfoKey, str]

info: LightInfo

print(info['does-not-exist'])

print(info['serial_number'])

IDE

Bildschirmfoto 2022-10-04 um 10 28 19

henryruhs avatar Oct 04 '22 08:10 henryruhs

Ok, can you speak to your motivation for digging thru the info dictionary looking for values? It will be difficult to provide these sorts of assurances since different devices populate different fields without any consistency. It appears you are looking for unique identifiers for each light ( serial_number and path so far in the examples you've given ). Not all lights have a serial number, in fact most do not. The path is an operating system artifact and device paths generally have a one to one relationship with devices.

I see the value of what you are asking but I'm not convinced that it solves the underlying problem, which you have not expressed.

JnyJny avatar Oct 04 '22 13:10 JnyJny

Could you at least provide dumped output for the light.info dict, light.path string and other unique properties for each device inside it's docs?

henryruhs avatar Oct 04 '22 22:10 henryruhs

Again, the question and answer dynamic is how I learn best when I don't understand something. What problem are you trying to solve that you need to use the inconsistent data in the Light.info dictionary property?

JnyJny avatar Oct 06 '22 02:10 JnyJny