BLEA : Playbulb Découverte automatique des caractéristiques => int() can't convert non-string with explicit base

Bonsoir,

Pour commencer :

  • Jeedom 4.0.61

  • RPI3 Stretch / VM Debian Buster => testé sur les deux

  • Testé avec les versions stable et Beta du plugin BLEA / Dépendances reinstallées

  • Clé SenaUD100

J’ai un petit souci avec une lampe Playbulb Garden

Elle est bien découverte mais les commandes ne fonctionnent pas.

J’obtiens cette erreur dans les logs :

[2020-11-05 22:22:01.615][DEBUG] : Creating a new connection for 97:19:4B:1A:AC:E6
[2020-11-05 22:22:01.616][DEBUG] : CONNECTOR------Connecting : 97:19:4B:1A:AC:E6 with bluetooth 0
[2020-11-05 22:22:01.862][DEBUG] : CONNECTOR------Connected... 97:19:4B:1A:AC:E6
[2020-11-05 22:22:01.863][DEBUG] : Not known handles searching
[2020-11-05 22:22:01.863][DEBUG] : Searching characteristics
[2020-11-05 22:22:01.864][DEBUG] : CONNECTOR------Getting Characteristics... 97:19:4B:1A:AC:E6
[2020-11-05 22:22:01.864][DEBUG] : int() can't convert non-string with explicit base

Cette erreur vient de la fonction getCharacteristics() du fichier /plugins/blea/resources/blead/multiconnect.py

et plus précisant de la ligne 136

char = self.conn.getCharacteristics(int(handle,16), int(handleend,16)+4)

qui est elle même appelée par findCharacteristics() dans le fichier /plugins/blea/resources/blead/devices/playbulb.py

	def findCharacteristics(self,mac,conn=''):
		logging.debug("Searching characteristics")
		if conn == '':
			conn = Connector(mac)
			conn.connect()
		if not conn.isconnected:
			conn.connect()
			if not conn.isconnected:
				return
		value=''
		characteristics=[]
		try:
			characteristics = conn.getCharacteristics(0x0001,retry=2)
		except Exception as e:
			logging.debug(str(e))
			try:
				characteristics = conn.getCharacteristics(0x0001,retry=2)
			except Exception as e:
				logging.debug(str(e))
				try:
					characteristics = conn.getCharacteristics(0x0001,retry=2)
				except Exception as e:
					logging.debug(str(e))
					conn.disconnect()
		color_characteristic = next(iter(filter(lambda el: el.uuid == COLOR_CHARACTERISTIC_UUID, characteristics)))
		effect_characteristic = next(iter(filter(lambda el: el.uuid == EFFECT_CHARACTERISTIC_UUID, characteristics)))
		logging.debug('Found ' + hex(color_characteristic.getHandle()) + ' ' + hex(effect_characteristic.getHandle()))
		return [hex(color_characteristic.getHandle()),hex(effect_characteristic.getHandle())]

D’après ce que je comprends, il faut que le handle soit une string lorsque la base est précisée et cela ne semble pas être le cas d’après le message d’erreur.

class int( x , base=10 )
Return an integer object constructed from a number or string x , or return 0 if no arguments are given. If x is a number, return x.int(). For floating point numbers, this truncates towards zero.
If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in radix base .

J’ai tenté de forcer la valeur en string soit en remplacant :

characteristics = conn.getCharacteristics(0x0001,retry=2)

par :

characteristics = conn.getCharacteristics(str('0x0001'),retry=2)

ou bien :

char = self.conn.getCharacteristics(int(handle,16), int(handleend,16)+4)

par

char = self.conn.getCharacteristics(int(str(handle),16), int(str(handleend),16)+4)

Dans les deux cas, l’erreur initiale disparait mais l’action echoue :

[2020-11-05 22:42:51.560][DEBUG] : Creating a new connection for 97:19:4B:1A:AC:E6
[2020-11-05 22:42:51.561][DEBUG] : CONNECTOR------Connecting : 97:19:4B:1A:AC:E6 with bluetooth 0
[2020-11-05 22:42:51.750][DEBUG] : CONNECTOR------Connected... 97:19:4B:1A:AC:E6
[2020-11-05 22:42:51.750][DEBUG] : Not known handles searching
[2020-11-05 22:42:51.751][DEBUG] : Searching characteristics
[2020-11-05 22:42:51.751][DEBUG] : CONNECTOR------Getting Characteristics... 97:19:4B:1A:AC:E6
[2020-11-05 22:42:51.946][DEBUG] : CONNECTOR------Characteristics gotten... 97:19:4B:1A:AC:E6
[2020-11-05 22:42:51.947][DEBUG] : ACTION------Action failed :

Si je force les valeurs des handles manuellement

	def findCharacteristics(self,mac,conn=''):
		logging.debug("Searching characteristics")
		if conn == '':
			conn = Connector(mac)
			conn.connect()
		if not conn.isconnected:
			conn.connect()
			if not conn.isconnected:
				return
		value=''
		characteristics=[]
		try:
			characteristics = conn.getCharacteristics(0x0001,retry=2)
		except Exception as e:
			logging.debug(str(e))
			try:
				characteristics = conn.getCharacteristics(0x0001,retry=2)
			except Exception as e:
				logging.debug(str(e))
				try:
					characteristics = conn.getCharacteristics(0x0001,retry=2)
				except Exception as e:
					logging.debug(str(e))
					conn.disconnect()
#		color_characteristic = next(iter(filter(lambda el: el.uuid == COLOR_CHARACTERISTIC_UUID, characteristics)))
		color_characteristic = '0x0025'
#		effect_characteristic = next(iter(filter(lambda el: el.uuid == EFFECT_CHARACTERISTIC_UUID, characteristics)))
		effect_characteristic = '0x0023'
#		logging.debug('Found ' + hex(color_characteristic.getHandle()) + ' ' + hex(effect_characteristic.getHandle()))
#		return [hex(color_characteristic.getHandle()),hex(effect_characteristic.getHandle())]
		return [color_characteristic,effect_characteristic]

les commandes fonctionnent bien car la découverte de ceux ci n’a plus besoin d’être faite.

[2020-11-05 22:50:28.833][DEBUG] : Creating a new connection for 97:19:4B:1A:AC:E6
[2020-11-05 22:50:28.834][DEBUG] : CONNECTOR------Connecting : 97:19:4B:1A:AC:E6 with bluetooth 0
[2020-11-05 22:50:29.247][DEBUG] : CONNECTOR------Connected... 97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.247][DEBUG] : Already known handles {'colorhandle': '0x0025', 'effecthandle': '0x0023'}
[2020-11-05 22:50:29.248][DEBUG] : CONNECTOR------Reading Characteristic...97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.345][DEBUG] : CONNECTOR------Characteristic Readen .... 97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.346][DEBUG] : UTILS------Converting to hex (0, 0, 0, 0, 255, 0, 10, 0)
[2020-11-05 22:50:29.346][DEBUG] : UTILS------Result is 00000000ff000a00
[2020-11-05 22:50:29.346][DEBUG] : CONNECTOR------Writing Characteristic... 97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.347][DEBUG] : CONNECTOR------Characteristic written... 97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.347][DEBUG] : {'rsp': ['wr']}
[2020-11-05 22:50:29.348][DEBUG] : Already known handles {'colorhandle': '0x0025', 'effecthandle': '0x0023'}
[2020-11-05 22:50:29.348][DEBUG] : Here is the list to refresh ['color', 'effect']
[2020-11-05 22:50:29.348][DEBUG] : CONNECTOR------Reading Characteristic...97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.443][DEBUG] : CONNECTOR------Characteristic Readen .... 97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.444][DEBUG] : UTILS------Converting to hex (255, 0, 0, 0)
[2020-11-05 22:50:29.444][DEBUG] : UTILS------Result is ff000000
[2020-11-05 22:50:29.445][DEBUG] : CONNECTOR------Reading Characteristic...97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.545][DEBUG] : CONNECTOR------Characteristic Readen .... 97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.545][DEBUG] : UTILS------Converting to hex (0, 0, 0, 0, 255, 0, 10, 0)
[2020-11-05 22:50:29.546][DEBUG] : UTILS------Result is 00000000ff000a00
[2020-11-05 22:50:29.546][DEBUG] : {'mode': 'Aucun', 'speed': 245, 'color': '#FFFFFF'}
[2020-11-05 22:50:29.546][DEBUG] : CONNECTOR------Disconnecting... 97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.548][DEBUG] : CONNECTOR------Disconnected...97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.549][DEBUG] : CONNECTOR------Disconnecting... 97:19:4B:1A:AC:E6
[2020-11-05 22:50:29.549][DEBUG] : CONNECTOR------Disconnected...97:19:4B:1A:AC:E6

Je dois louper un truc quelquepart mais je ne vois pas quoi.

Si quelqu’un à une idée, je suis preneur.

PS : Je vois que les mêmes fonctions de découvertes sont utilisées pour les nuts mais n’en ayant pas, je ne peux pas tester pour comparer.

Bon finalement le cast avec str() semble bien fonctionner mais c’est le fait de spécifier un handle de fin qui pose problème.

En remplacant dans /plugins/blea/resources/blead/multiconnect.py :

char = self.conn.getCharacteristics(int(handle,16), int(handleend,16)+4)

par

char = self.conn.getCharacteristics(int(str(handle),16))

cela fonctionne mais multiconnect.py etant utilisé globalement, je ne sais pas quel impact cela pourrait avoir sur le fonctionnement global du plugin (même si cela serait probablement limité car cette fonction getCharacteristics() ne semble être utilisé que pour les Playbulb, Nut et Aqualin).

En comparant avec le fichier /plugins/blea/resources/blead/devices/aqualin.py, on peut voir que le handle n’est pas forcément necessaire.

Du coup, dans le fichier /plugins/blea/resources/blead/devices/playbulb.py, en remplacant :

characteristics = conn.getCharacteristics(0x0001,retry=2)

par

characteristics = conn.getCharacteristics()

cela fonctionne également (sans avoir besoin de modifier /plugins/blea/resources/blead/multiconnect.py) mais cela me plait mieux car dans ce cas, la correction est à faire uniquement dans la fonction specifique au playbulb.

Maintenant la question est de savoir si cela doit être mofidié pour tout les Playbulb ou bien est ce que cela est spécifique au modèle Garden ou encore à la version software de celle-ci (BTL400M_V2.3)

Y aurait-il des utilisateurs de Playbulb Garden ou autre modèle de Playbulb qui pourraient faire le test ?

Salut,

intéressant comme analyse, en ayant tout lu je pense que la conversion en str() ne peut pas faire de mal, au contraire, avant l’appel à int(x, base).
Mais par contre suivant la doc on peut quand même comprendre que si x est un nombre déjà (entier ou réel), il sera simplement retourné donc cela ne devrait rien changer;
sur quelle version de python as-tu testé?

Je te rejoins sur le fait que ca réduit le risque d’impact.

Je n’ai pas de playbulb mais j’ai des nuts, qui fonctionnent comme voulu, je suppose que le test que tu voulais faire c’est avec le changement str() … ou alors tu laisses tomber complétement cette piste pour réduire l’impact comme dit juste avant?

Je suis d’accord avec toi mais la valeur passée étant « 0x0001 », je ne pense pas que l’on puisse considérer qu’il s’agisse d’un entier ou d’un réel.

De plus, si je comprends bien (mais j’interprête peut être mal la doc), à partir du moment ou une base est spécifiée, on a pas le choix, il faut que x soit une string.

Pour les versions de python, j’ai pensé à y jeter un oeil à un moment et puis j’ai zappé.

Sur le RPI3, j’ai :

root@raspberrypi:~# python --version
Python 2.7.13
root@raspberrypi:~# python3 --version
Python 3.5.3

et sur la VM

root@jeedom:~# python --version
Python 2.7.16
root@jeedom:~# python3 --version
Python 3.7.3

Concernant le test, je parlais de supprimer les paramètres dans l’appel à la fonction getCharacteristics() dans le fichier playbulb.py ou nut.py.

En remplacant :

characteristics = conn.getCharacteristics(0x0001,retry=2)

par

characteristics = conn.getCharacteristics()

En revanche, pour faire ce tests, il faut supprimer l’équipement avant puis le recréer car l’utilisation de cette fonction ne se fait qu’une seule fois à la première commande que l’on envoie. Une fois que les handles ont été découverts, ils sont stockés dans l’objet

Oui je suis d’accord, la doc est ambiguë, on peut l’interpréter des deux façons, c’est ce que je voulais dire.

Il semblerait qu’il y ait eu une modification de comportement dans la version 3.4 de python concernant l’utilisation de la base :

Modifié dans la version 3.4: Si base n’est pas une instance d’ int et que base a une méthode base.__index__ , cette méthode est appelée pour obtenir un entier pour cette base. Les versions précédentes utilisaient base.__int__ au lieu de base.__index__ .

J’ai tenté de modifier la version de python par défaut pour utiliser la 2.7 afin de faire un test

root@raspberrypi:~# update-alternatives --config python
There are 2 choices for the alternative python (providing /usr/bin/python).

  Selection    Path                Priority   Status
------------------------------------------------------------
  0            /usr/bin/python3.5   2         auto mode
* 1            /usr/bin/python2.7   1         manual mode
  2            /usr/bin/python3.5   2         manual mode

mais je ne suis pas sur que cela soit pris en compte par le plugin BLEA.

Comment savoir quelle version de Python utilise le plugin BLEA ?

EDIT : D’après le fichier d’install des dependances, je vois que c’est python 3 qui est utilisé par le plugin. Il faudrait que je fasse le test avec une version 3.X inférieur à la 3.4 et pas avec une version 2 si je comprends bien. En revanche, la version 3.4 était pour Jessie et je n’ai plus de machine en Jessie. Possible d’installer la version python3.4 sur Stretch ou Buster ?

Oui il faut python3 pour blea.
Et je ne sais pas dire pour la 3.4.
De toute façon ça ne sera pas une solution en soit puisque c’est une ancienne version

Bon, python 3.3 ne veut pas s’installer sur Stretch.

Du coup, j’ai remonté rapidement une VM sous Jessie mais c’est la version 4 de Jeedom qui ne s’installe plus sous Jessie.

A moins de resintaller un Jeedom 3.x sur un Jessie mais on s’eloigne tellement que je ne suis pas sur que le test soit concluant et valide.

Si Ludovic passe par là, il pourra peut être nous aiguiller …