" /> Mon para-monde
Flux RSS

lundi 19 mars 2012

ELV Max! Il est temps de passer commande

Excusez la blague à 2 balles, il n'est bien sûr pas question d'acheter quelque chose mais de trouver les commandes que le cube peut recevoir et les réponses qu'il peut fournir.

On a déjà vu quelques commandes :

Le sniffing du réseau et le classique essai/erreur permettent d'en trouver quelques autres :

  • "m:" qui modifie les données de la M:aison
  • "z:" qui est envoyé avant un groupe de commandes
  • "n:" qui met le cube en mode apprentissage
  • "x:" annule une commande en cours de type "n:"
  • "d:" et "e:" qui décodent et encodent une chaine binaire (quel algorithme ? mystère)

Comme les lignes reçues, la macrosyntaxe est <lettre de commande>:<enchaînement de champs séparés par des virgules>.

Dans les champs, les données sont soit codées en hexadécimal ou en texte brut (p. exemple : "z:1e,G,02" ) soit encodées partiellement ou totalement en base64 (p. exemple : "s:AAAAiAAAAAPx4AAI=" )

Toutes les commandes que je trouverai seront rajoutées ici au fur et à mesure avec des liens vers chaque description.

dimanche 18 mars 2012

Quelques ordres S: (S12,S20,S21,S22,S23)

J'ai été très occupé ces derniers temps, pas eu trop le temps d'écrire les articles sur d'autres fonctions S:(end) de l'ELV Max!

En voici quelques unes :

ConfigValve (Commande 0x12)

00     00
01     Bitfield : 76543210
                       10 = broadcast (?)
02     12    COMMANDE
03     00
04     00
05     00
06     AABBCC Adresse d'émission
07     ..
08     ..
09     XX     RoomId
10     XX     Configuration du Boost (1)
11     XX     Configuration du cycle de détartrage (2)
12     XX     Position Max de la valve
13     XX     Position Min de la valve

(1) La configuration du Boost se fait sur un octet sous forme de 2 champs de bits :

  • 3 bits pour la durée du Boost en tranche de 5min
  • 5 bits pour l'ouverture de valve en tranche de 5%

(2) Le détartrage se règle lui aussi sur un champ de 8 bits :

  • 3bits pour le jour (0=Samedi, 1=Dimanche... 6=Vendredi)
  • 5bits pour l'heure de mise en route par tranche de 30 minutes

AddDirectLinkFromTo (0x20) et RemoveDirectLinkFromTo (0x21)

00     00
01     Bitfield : 76543210
                       10 = broadcast (?)
02     20/21    COMMANDE
03     00
04     00
05     00
06     AABBCC Adresse d'émission du périphérique référence
07     ..
08     ..
09     AABBCC Adresse d'émission du périphérique de pilotage
10     ..
11     ..
12     XX Type de périphérique

setGroupRFaddr (0x22) et removeGroupRFaddr (0x23)

00     00
01     Bitfield : 76543210
                       10 = broadcast (?)
02     22/23    COMMANDE
03     00
04     00
05     00
06     AABBCC Adresse d'émission du périphérique à ajouter ou retirer de la pièce
07     ..
08     ..
09     XX     RoomId

On a pas fini, il reste encore quelques commandes s:, en particulier le réglage des programmes journaliers (mode 0x10) et le changement de modes (mode 0x40) qui sont incontournables et un peu velus.

lundi 13 février 2012

ELV Max! commande "s:" syntaxe générale et commande de réglage des températures par défaut (0x11)

La commande "s:" sert à envoyer une commande (send en anglais quoi).

Le format général est s:<chaine en base64>

Pour illustrer voici la commande générée par la modification du décalage de température sur un thermostat dont l'adresse est 00fb6d.

s:AAARAAAAAPttACoiPQkJGAM=

Le décodage ramène une chaine binaire (ici en hexa) :

00 00 11 00 00 00 00 fb 6d 00 2a 22 3d 09 09 18 03
#0 #1 #2 #3 #4 #5 #6 #7 #8 #9 #A #B #C #D #E #F #10

Si on décortique, en premier lieu, on trouve tout de suite à partir de #6 une adresse de périphérique.

Une modification du même paramètre fait varier uniquement l'octet #E tandis que le changement d'autres paramètres de température font varier individuellement les autres octets de #A à #10.

Ces valeurs ne sont cependant pas encodées directement. Ainsi une température qui se règle par pas de 0,5° et encodée sous la forme T°x2 et le décalage de température qui peut aller de -3,5 à 3,5 est encodé par dT°x2+7 .

Au final voici le payload de la fonction 11(hex) :

00     00
01     Bitfield : 76543210
                       10 = broadcast (?)
02     11    COMMANDE (ici réglage des températures par défaut)
03     00
04     00
05     00
06     AABBCC Adresse d'émission
07     ..
08     ..
09     XX     RoomId
10     XX     Température de comfort
11     XX     Température éco
12     XX     Température max réglable sur la tête
13     XX     Température min réglable sur la tête
14     XX     Décalage de température
15     XX     Température lorsqu'une fenêtre est ouverte
16     XX     Durée de la consigne de fenêtre ouverte

Le retour de l'envoi d'une telle commande est une ligne "S:"

Celle-ci contient 3 champs séparés par des virgules :

1 : Ce chiffre semble augmenter de temps en temps
2 : Succés/Echec (0/1)
3 : Ce chiffre diminue au maximum de 1 à chaque commande passée, il peut aussi augmenter le maximum est 30(hex) soit 48(dec).

Je pense que les commandes sont envoyées aux têtes par bloc ou par cycles, le champ 1 identifie le bloc courant et le 3 le nombre d'emplacements libres dans ce bloc. C'est pour cela que le champ 3 ne diminue pas toujours ; des commandes sont envoyées en même temps que d'autres sont reçues.

dimanche 5 février 2012

ELV Max! Contenu de la ligne L:ive

A la différence des lignes de C:onfig qui sont aussi nombreuses qu'il y a de périphériques branchés, la ligne L:ive est unique. Tous les périphériques sont regroupés en une seule ligne.

Par ailleurs il n'y a pas d'information sur le cube dans la ligne L:

Interogation du cube

On peut demander une nouvelle ligne L:ive mise à jour par l'envoi de "l:" (L minuscule) suivi de CR+LF Le cube répond alors par une ligne L: contenant les dernières données dont il dispose.

Structure générale d'une ligne L:

La ligne L: ne possède qu'un champ encodé en Base64

par exemple :
L:CwD7bQASGEcpAAAA

Contenu du champ

L'exemple ci-dessus se décode en :

0b 00 fb 6d 00 12 18 47 29 00 00 00

On repère tout de suite les octets 2,3,4 "00fb6d" correspondant à une adresse. Par ailleurs, le premier octet contient 0x0b correspondant au nombre d'octets qui suivent (lorsqu'il y a plusieurs périphériques connectés, on retrouve à nouveau cette même structure <longueur><contenu> répétée autant de fois qu'il y a de périphériques.

On remarque aussi, pas mal d'octets à 0x00, ca va pas nous aider à dépiauter la bêêête mais ça s'arrange après avoir modifier des éléments de config :) .

Position     Champ
0              1 octet  = longueur du morceau de réponse suivant (je n'ai rencontré que des enregistrements de 11 caractères : 0x0b)
1              3 octets = Adresse
4              1 octet  = ? 
5              1 octet  = ? 
6              1 octet  = ? 
                  bits 1-2 = ?
                  bit 3    = Verrouillage clavier
                  bits 4-6 = ?
                  bits 7-8 = Mode
7              1 octet  = Position de la valve (0-100)
8              1 octet  = Température de consigne réglée sur la tête
9-10           2 octets = Date de fin
11             1 octet  = Heure de fin

Les octets 4-6 ne sont pas souvent modifiés par des actions par la webapp ou par modification des réglages de la tête, les seuls bits modifiés de façon synchrone sont sur l'octet 6 (bits 7 et 8) et correspondent au mode (0b00 : mode auto, 0b01 : mode manu, 0b10 : mode temporaire, 0b11 : mode Boost)

Date et heure ne sont valides que lorsqu'on est en mode "temporaire".

ELV Max! Contenu de la config (ligne C:)

La ligne C: se décompose en 2 champs principaux. Outre l'entête "C:", on retrouve le code d'adressage en hexadécimal sur 6 caractères (donc une fois retransformé, sur 24bits) suivi d'une virgule et à nouveau un contenu encodé en Base64.

C:007ead,7QB+rQAJAQBJRVEwMTEyMjQwAAsABEAAAAAAAAAAAP///////////////////////////wsABEAAAAAAAAAAQf///////////////////////////2h0dHA6Ly93d3cubWF4LXBvcnRhbC5lbHYuZGU6ODAvY3ViZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENFVAAACgADAAAOEENFU1QAAwAAAAAcIA==

Voici donc la ligne correspondant au périphérique 007ead. Dans le cas présent, il s'agit du cube lui-même et je n'en étudierai pas la config tout de suite car peu intéressante, pour le plaisir voici le décodage (les données alphanumériques sont soulignées, le reste est en hexadécimal) :

ED 007EAD 00 09 01 00 IEQ0112240 00 0B 00 04 40 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 0B 00 04 40 00 00 00 00 00 00 00 41 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF http://www.max-portal.elv.de:80/cube 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 CET 00 00 0A 00 03 00 00 0E 10 CEST 00 03 00 00 00 00 1C 20

On y découvre entre autre l'URL du backend du portail web (l'adresse du frontend est à http://www.max-portal.elv.de/ ).

Intéressons-nous plutôt aux thermostats.

La config est là-aussi contenue dans un champ encodé en base64. Celle-ci étant particulièrement longue, je vous en fait grâce et je vais me contenter d'en faire le détail :

Position     Champ
0              1 octet  = ?
1              3 octets = Adresse
4              1 octet  = Type de périphérique (0=Cube?, 1=Thermostat)
5              1 octet  = ?
6              10 octets= Numéro de série (IEQXXXXXXX)
16             1 octet  = Température de confort (*)
17             1 octet  = Température Eco (*)
18             1 octet  = Température maximale de réglage (4.5° soit 0x09 = valeur de 'off')
19             1 octet  = Température minimal de réglage (30.5° soit 0x3d = valeur de 'on')
20             1 octet  = Décalage de réglage température (*)
21             1 octet  = Température en cas d'ouverture de fenêtre (*)
22             1 octet  = Durée de changement de consigne en cas d'ouverture de fenêtre (*)
23             1 octet  = bitfield de 8 bits
                3 bits   = durée du Boost (*)
                 5 bits   = valeur de valve du Boost (*)
24             1 octet  = bitfield de 8 bits
                3 bits   = Jour du cycle de détartrage de la valve (*)
                 5 bits   = heure de détartrage de la valve (*)
25             1 octet  = position maximum de la valve ? (255) peut-être dépendant du réglage initial de course
26             1 octet  = position de départ de la valve ? (0) peut-être dépendant du réglage initial de course
27             début des programmes journaliers (7 groupes = 1 par jour) (*)
(*) les valeurs sont modifiables depuis la webapp

Les températures sont exprimées en multiples de 0,5° (Température = Valeur/2)

La liste des jours commence le Samedi(=0 ???) jusqu'au Vendredi (=7)

Le décalage de température est exprimé en multiples de 0,5° à ajouter à -3,5° (Décalage = Valeur/2 - 3.5)

La durée du boost se calcule donc par Durée = (Valeur & 0xE0)>>5 et la valeur de valve par Valve = (Valeur & 0x1F)

Idem pour le détartrage : Jour = (Valeur & 0xE0)>>5 et Heure = (Valeur & 0x1F)

Un programme journalier est constitué de 26 octets, 13 blocs de 2 octets pour être plus précis soit 13 paliers programmables par jour. Sur ses 16bits (composant les 2 octets MSB et LSB), sont encodées 2 grandeurs : la température de consigne et l'heure de fin.

0TTTTTTH.HHHHHHHH

La Température est à nouveau exprimée en multiple de 0,5 tandis que l'heure est exprimée en multiple de 5 minutes

Donc partant du principe qu'on lit les octets un par un, on a :

Température = ((MSB & 0x7E)>>1)/2
Heure de fin = ((MSB & 0x01)*256+LSB)*0.5

Il me reste donc 2 champs dont je n'arrive pas à comprendre la signification (0 et 5).

Demander une ligne de C:onfig

Il est possible de demander la ligne de configuration d'un périphérique spécifique si on connait son adresse.

Pour cela il faut envoyer la commande "c:" suivie de l'adresse en hexadécimal par exemple (terminer par CR+LF) :

c:007ead
C:007ead,<........................>

Le résultat est la ligne C: telle qu'on peut la voir en haut de l'article. Si l'adresse est inconnue, il n'y a pas de réponse.

Méthodologie

La méthode pour repérer tout cela est principalement de lancer depuis l'interface web des commandes unitaires puis de récupérer la configuration immédiatement après afin d'isoler les différences et d'en tirer une signification.

Pour les champs non modifiables (température maxi ou min), il faut faire des essais ("si c'était une température, si je divise par 2 est-ce que ca donne une valeur qui a du sens ?") éventuellement avec le manuel pas loin

samedi 28 janvier 2012

J'ai découvert une commande de plus sur ELV Max!, ben j'aurais préféré m'en passer... :)

Alors que je bidouillais le Cube via netcat, j'ai lancé quelques commandes de la forme <lettre><:><cr><lf>

Et bien, ca m'a permis de découvrir à mon corps défendant la commande "a:" que l'on peut désormais surnommer "Reset sauvage de toute les métadonnées".

4 petits caractères suffisent à ramener le cube dans un état immaculé :

H:IEQ0112240,007ead,0109,00000000,2ee8c053,00,32,0c011c,0c2b
M:
C:007ead,7QB+rQAJAQBJRVEwMTEyMjQwAAsABEAAAAAAAAAAAP///////////////////////////wsABEAAAAAAAAAAQf///////////////////////////2h0dHA6Ly93d3cubWF4LXBvcnRhbC5lbHYuZGU6ODAvY3ViZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENFVAAACgADAAAOEENFU1QAAwAAAAAcIA==
L:

On voit le champ M: vide, l'absence de données L:ive et une seule ligne de config pour le Cube lui-même...

La bonne nouvelle, c'est qu'après avoir fait le réapprentissage d'un thermostat, il semble que la config soit retrouvée (retéléchargée du la tête ?)

H:IEQ0112240,007ead,0109,00000000,233903cd,04,32,0c011c,0d04
M:00,01,VgIBAQZCdXJlYXUA+20BAQD7bUlFUTAxODQ5OTkHQnVyZWF1MQEB
C:007ead,7QB+rQAJAQBJRVEwMTEyMjQwAAsABEAAAAAAAAAAAP///////////////////////////wsABEAAAAAAAAAAQf///////////////////////////2h0dHA6Ly93d3cubWF4LXBvcnRhbC5lbHYuZGU6ODAvY3ViZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENFVAAACgADAAAOEENFU1QAAwAAAAAcIA==
C:00fb6d,0gD7bQEBFP9JRVEwMTg0OTk5KiI9CQcYAzAM/wBESFUIRSBFIEUgRSBFIEUgRSBFIEUgRSBFIERIVQhFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhUbETMVRRFIEUgRSBFIEUgRSBFIEUgRSBESFRsRMxVFEUgRSBFIEUgRSBFIEUgRSBFIERIVGxEzFUURSBFIEUgRSBFIEUgRSBFIEUgREhUbETMVRRFIEUgRSBFIEUgRSBFIEUgRSBESFRsRMxVFEUgRSBFIEUgRSBFIEUgRSBFIA==
L:CwD7bQASGEcpAAAA

On peut noter au passage que le champ 6 de H: a changé (00 -> 04) mais je ne sais pas pourquoi..

vendredi 27 janvier 2012

ELV MAX! Lignes Host (H:) et Maison (M:)

Revenons à l'étude de la réponse initiale du Cube Max!

Le format le plus global est :

  • un ensemble de lignes commençant toutes par une lettre suivie d'un "deux points" lui même suivi d'un contenu
  • chaque ligne est terminée par un marqueur assez classique : cr/lf (carriage return/line feed)

Voici ce que j'ai pu tirer pour l'instant des lignes H et M

H:

Contient des données très basiques sur le système : Les champs du contenu sont séparés par des virgules

H:IEQ0112240,007ead,0109,00000000,35e2322f,00,32,0c011b,0909

que l'on peut découper en :

  • IEQ0112240 = numéro de série du Cube (invariant dans la même installation, il est imprimé sous le cube), format alphanumérique
  • 007ead = nombre constant (on le retrouve ailleurs sur la première ligne C:, on le verra plus tard), c'est donc d'une certaine manière un moyen d'adressage, format hexadécimal sur 3 octets
  • 0109 = la version du microcode embarqué a priori (le code a changé après une mise à jour)
  • 00000000 = euh comment dire... des zéros ?
  • 35e2322f = un nombre variant totalement à chaque connexion, probablement un identifiant de connexion mais on ne le retrouve nulle par ailleurs, format hexadécimal sur un long (32bits)
  • 00 = encore des 0... impossible d'en savoir la signification
  • 32 = toujours 32 là aussi... impossible d'en tirer une conclusion
  • 0c011b = là aussi un invariant
  • 0909 = Est-ce que ca ne serait pas 9 heures 09 (si c'est le cas, le cube n'est pas à l'heure :) ), à voir lorsqu'on passera

M:

M:00,01,VgIHAQdDdWlzaW5lAP4uAgtTYWxsZSBkJ2VhdQD99QMNQ2hhbWJyZSBMdWNhcwCWrAQTQ2hhbWJyZSBGcmVkIExvdWxvdQCZbwUGQnVyZWF1APttBg1TYWxsZSBkZSBiYWluAPx4BwVTYWxsZQCWkgcBAP4uSUVRMDE4NDgxMgdDdWlzaW5lAQEA/fVJRVEwMTg0NzQ0C1NhbGxlIGQnZWF1AgEAlqxJRVEwMTg2MTYyDUNoYW1icmUgTHVjYXMDAQCZb0lFUTAxODMzMTcTQ2hhbWJyZSBGcmVkIExvdWxvdQQBAPttSUVRMDE4NDk5OQZCdXJlYXUFAQD8eElFUTAxODUxNjYNU2FsbGUgZGUgYmFpbgYBAJaSSUVRMDE4NjExNw9TYWxsZSDDoCBtYW5nZXIHAQ==

La ligne M: là aussi contient des champs séparés par des virgules. Et là aussi les 2 premiers sont invariants d'une connexion à l'autre (toujours 00 et 01) Suit un champ beaucoup plus long qui semble codé mais on note qu'on a affaire à des caractères tous "imprimables" et qu'en fin de ligne on retrouve des "=" typiques du remplissage final en base64

Si on décode ce 3ème champ comme du base64 on récupère en effet un contenu contenant des éléments reconnaissables et cohérents (les caractères non imprimables ont été supprimés) :

V(...)Cuisine(...)Salle d'eau(...)Chambre Lucas(...)Chambre Fred Loulou(...)Bureau(...)Salle de bain(...)Salle(...)IEQ0184812 Cuisine(...)IEQ0184744 Salle d'eau(...)IEQ0186162 Chambre Lucas(...)IEQ0183317 Chambre Fred Loulou(...)IEQ0184999 Bureau(...)IEQ0185166 Salle de bain(...)IEQ0186117 Salle à manger(...)

Dans ce contenu binaire on peut retrouver une certaine organisation : Il y a 3 sous-ensembles.


** un préambule de 2 octets au contenu inconnu
** une structure décrivant les pièces (organisation logique)
** une structure décrivant les périphériques (organisation physique)

Format de la liste des pièces

Le premier octet contient le nombre de pièces définies (roomCount). A sa suite, on retrouve répétée roomCount fois une structure définissant une pièce :

  • Nombre de caratères du nom de la pièce (1 octet)
  • Nom de la pièce (X octets cf supra)
  • ID de la pièce (1 octet)
  • 3 octets dont le contenu ressemble au champ qualifié d'adressage sur la ligne H:, mais il ne semble pas utilisé (ID est utilisé ensuite)

Immédiatement après la liste des pièces on attaque la liste des périphériques (thermostats) Le principe est le même que la liste des pièces.

Format de la liste des périphériques

Le premier octet contient le nombre de périphériques définis (devCount).

La aussi on retrouve devCount fois une structure de périphérique :

  • Type de périphérique (1 octet) 0=Cube, 1=Tête thermostatique, peut-être y en a t'il d'autres pour par exemple le thermostat mural (mais je n'en ai pas)
  • 3 octets "d'adressage", le contenu de ce champ se retrouve comme premier champ des lignes C: suivantes permettant de les rattacher à un périphérique
  • 10 octets de numéro de série
  • 1 octet de nombre de caractères du nom du périphérique
  • Nom du périphérique (X octets ci-dessus)
  • ID de la pièce de rattachement (1 octet)

Voilà, avec la ligne M: on peut construire la structure de notre maison.

La prochaine fois, je m'attaque à la ligne C: qui donne la config courante d'un périphérique.

mercredi 25 janvier 2012

ELV MAX! Début d'exploration

Je vais vous épargner le détail de la méthodologie mais pour faire simple. Il faut sniffer le réseau entre l'appli java qui réside sur l'ordinateur et le boîtier. Pour cela, j'ai fait brutal (parce que bien sur l'appli ne marche que sous Windows) : j'ai intercalé un ordi entre les 2, mis en place l'IP forwarding et lancé mon fidèle wireshark (un logiciel de capture de trame réseau et d'analyse). On peut aussi bien sur capturer directement sur l'ordinateur "source".

Voici les premiers constats :

  • l'appli se connecte à son lancement au cube sur le port 80, on se dit alors Chouette il y a un serveur web embarqué. Hélas on déchante vite car une fois l'appli connectée, impossible d'initier une autre connexion TCP/IP vers le port 80. Le cube ne supporte qu'un seul logiciel de commande à la fois...
  • il ne s'agit pas de HTTP non plus. En effet, toute connexion même sans envoi de requête génère une réponse du cube. Voici un exemple de réponse à l'ouverture d'une connexion (sans rien envoyer) :
H:IEQ0112240,007ead,0109,00000000,673a0152,00,32,0c0110,1306

M:00,01,VgIHAQdDdWlzaW5lAP4uAgtTYWxsZSBkJ2VhdQD99QMNQ2hhbWJyZSBMdWNhcwCWrAQTQ2hhbWJyZSBGcmVkIExvdWxvdQCZbwUGQnVyZWF1APttBg1TYWxsZSBkZSBiYWluAPx4BwVTYWxsZQCWkgcBAP4uSUVRMDE4NDgxMgdDdWlzaW5lAQEA/fVJRVEwMTg0NzQ0C1NhbGxlIGQnZWF1AgEAlqxJRVEwMTg2MTYyDUNoYW1icmUgTHVjYXMDAQCZb0lFUTAxODMzMTcTQ2hhbWJyZSBGcmVkIExvdWxvdQQBAPttSUVRMDE4NDk5OQZCdXJlYXUFAQD8eElFUTAxODUxNjYNU2FsbGUgZGUgYmFpbgYBAJaSSUVRMDE4NjExNw9TYWxsZSDDoCBtYW5nZXIHAQ==

C:007ead,7QB+rQAJAf9JRVEwMTEyMjQwAAsABEAAAAAAAAAAAP///////////////////////////wsABEAAAAAAAAAAQf///////////////////////////2h0dHA6Ly93d3cubWF4LXBvcnRhbC5lbHYuZGU6ODAvY3ViZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENFVAAACgADAAAOEENFU1QAAwACAAAcIA==

C:00fdf5,0gD99QECFP9JRVEwMTg0NzQ0KCA9CQcYAzAM/wBESFiFRNhY8FEDRSBFIEUgRSBFIEUgRSBFIERIWIZE2VEDRSBFIEUgRSBFIEUgRSBFIEUgREhYbETeWORRAkUgRSBFIEUgRSBFIEUgRSBESFhsRN5Y5FD3RSBFIEUgRSBFIEUgRSBFIERIWGxE2VEDRSBFIEUgRSBFIEUgRSBFIEUgREhYbETeWORRAkUgRSBFIEUgRSBFIEUgRSBESFhsRNhRFUUgRSBFIEUgRSBFIEUgRSBFIA==

C:0096ac,0gCWrAEDFP9JRVEwMTg2MTYyKCA9CQcYAzAM/wBEYFD+RSBFIEUgRSBFIEUgRSBFIEUgRSBFIERgUP5FIEUgRSBFIEUgRSBFIEUgRSBFIEUgQElUYkDTUQVBIEEgQSBFIEUgRSBFIEUgRSBASVRiQNNRBUEgQSBBIEUgRSBFIEUgRSBFIERgUP5FIEUgRSBFIEUgRSBFIEUgRSBFIEUgQElUYkDTUQVBIEEgQSBFIEUgRSBFIEUgRSBASVRiQNNRBUEgQSBBIEUgRSBFIEUgRSBFIA==

C:00fb6d,0gD7bQEFFP9JRVEwMTg0OTk5KCA9CQcYAzAM/wBEVFEKRSBFIEUgRSBFIEUgRSBFIEUgRSBFIERUUQpFIEUgRSBFIEUgRSBFIEUgRSBFIEUgRFRRCkUgRSBFIEUgRSBFIEUgRSBFIEUgRSBEVFEKRSBFIEUgRSBFIEUgRSBFIEUgRSBFIERUUQpFIEUgRSBFIEUgRSBFIEUgRSBFIEUgRFRRCkUgRSBFIEUgRSBFIEUgRSBFIEUgRSBEVFEKRSBFIEUgRSBFIEUgRSBFIEUgRSBFIA==

C:00fc78,0gD8eAEGFP9JRVEwMTg1MTY2KCA9CQcYAzAM/wBFIEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBFIETRVPBFIEUgRSBFIEUgRSBFIEUgRSBFIEUgPSA9ID0gPSA9ID0gPSBFIEUgRSBFIEUgRSA9ID0gPSA9ID0gPSA9IEUgRSBFIEUgRSBFID0gPSA9ID0gPSA9ID0gRSBFIEUgRSBFIEUgPSA9ID0gPSA9ID0gPSBFIEUgRSBFIEUgRSA9ID0gPSA9ID0gPSA9IEUgRSBFIEUgRSBFIA==

C:00996f,0gCZbwEEFP9JRVEwMTgzMzE3KCA9CQcYAzAM/wBEYFR0ROpRFEUgRSBFIEUgRSBFIEUgRSBFIERgVHRE6lEURSBFIEUgRSBFIEUgRSBFIEUgREhUYkTSVQNFIEUgRSBFIEUgRSBFIEUgRSBESFRiRNJVA0UgRSBFIEUgRSBFIEUgRSBFIERgVHRE6lEURSBFIEUgRSBFIEUgRSBFIEUgREhUYkTSVQNFIEUgRSBFIEUgRSBFIEUgRSBESFRiRNJVA0UgRSBFIEUgRSBFIEUgRSBFIA==

C:00fe2e,0gD+LgEBFP9JRVEwMTg0ODEyKCA9CQcYAzAM/wBEVFR4UMBU8EUgRSBFIEUgRSBFIEUgRSBFIERUVHhQwFTwRSBFIEUgRSBFIEUgRSBFIEUgRE9UbUzbVPBFIEUgRSBFIEUgRSBFIEUgRSBET1RtTNtU8EUgRSBFIEUgRSBFIEUgRSBFIERPVG1M21TwRSBFIEUgRSBFIEUgRSBFIEUgRE9UbUzbVPBFIEUgRSBFIEUgRSBFIEUgRSBET1RtTNtU8EUgRSBFIEUgRSBFIEUgRSBFIA==

C:009692,0gCWkgEHFP9JRVEwMTg2MTE3KCA9CQcYAzAM/wBEVFUJRSBFIEUgRSBFIEUgRSBFIEUgRSBFIERUVQlFIEUgRSBFIEUgRSBFIEUgRSBFIEUgRFRVCUUgRSBFIEUgRSBFIEUgRSBFIEUgRSBEVFUJRSBFIEUgRSBFIEUgRSBFIEUgRSBFIERUVQlFIEUgRSBFIEUgRSBFIEUgRSBFIEUgRFRVCUUgRSBFIEUgRSBFIEUgRSBFIEUgRSBEVFUJRSBFIEUgRSBFIEUgRSBFIEUgRSBFIA==

L:CwD99QkSGA0oAN0ACwCWrAkSGAAoAN8ACwD7bQkSGAAnANcACwD8eAkSGAAeAKkACwCZbwkSGAAqAP8ACwD+LgkSGC8qAM8ACwCWkgkSGGQqAMsA
  • Les paramètres comme on peut le voir ne sont pas très intuitifs, il va falloir creuser.
  • Certains éléments sont invariants et permettent d'avoir quelques indices : Le premier champ de la ligne H: reprend exactement le numéro de série situé sous le Cube. Je l'appelle ligne "Hôte" ("Host" en anglais)
  • L’enchaînement de ces lignes est immuable mais certains éléments varient beaucoup (par exemple le 5ème champ de la ligne H: différent à chaque reconnexion et ne semblant suivre aucune logique de progression) ou peu (Le contenu de la ligne L: )
  • Les données situées après la virgule des lignes C: sont probablement des données spécifiques à chaque élément du système (1 ligne par élément) car on trouve 8 lignes dans 2 formats (1 ligne dans 1 format et 7 dans un autre) et j'ai 7 thermostats et 1 cube. De plus la ligne H: qui contient le n° de série du Cube possède en champ 2 "007ead" présent en entête de la ligne C: dont le format diffère des autres. A priori ces données ne varient pas si on ne dérègle rien dans l'appli, j'imagine que ce sont les lignes de configuration. Petit nom, "Config".

Il va falloir décoder ces lignes maintenant.

Si on continue de suivre le fil des événements réseaux, l'appli envoie des commandes "l:" qui entraînent la réémission d'une ligne "L:" qui au bout d'un certain temps peut discrètement varier. J'imagine qu'il s'agit des données "live", zou voila le nom trouvé. La ligne M... faut voir...

Au final on se sent revenu au bon vieux temps où la place disque/réseau/ram était chère. On va pouvoir s'amuser ! :)

mardi 24 janvier 2012

Domotiqueuh tiqueuh tiqueh

Non, je ne me transforme pas en Soeur sourire mais depuis quelques mois j'avais mis en place des corps thermostatiques sur certains des radiateurs de la maison et en ce début d'année, j'y ai installé les têtes thermostatisques adaptées

lundi 16 janvier 2012

Rechute de geek : Arduino

Ca y est j'ai fait une rechute...

Pour mon anniv, je me suis fait payer un Arduino.

Pour ceux qui ne savent pas ce que c'est c'est un petit "ordinateur" minimaliste prévu pour l'interfaçage avec le monde extérieur via un peu d'électronique.

Le modèle que j'ai pris est un Arduino Ethernet. De taille réduite -qu'on pourrait en tenir 2 côte à côte dans la main- il embarque tout de même 1 port Ethernet, 1 lecteur de microSD/Transflash et une petite seizaine de ports d'entrée sortie digitaux et analogiques.

A moi tout plein d'expérimentations et d'heures perdues :) !

jeudi 3 mars 2011

Présenter proprement la playlist TV de Free pour regarder la TV sur un iPad

Ma femme a un iPad depuis quelques temps qui a été jailbreaké dans la foulée de l'achat.

Cela a permis d'installer VLC afin de passer outre aux limitations intrinsèques du player Apple.

Or VLC sur iPad c'est un peu pas facile à utiliser, il n'y a pas d'interface pour saisir un chemin réseau et il faut déposer à la mimine en SFTP les fichiers au bon endroit.

Alors de là à pouvoir rentrer un lien RTSP voire pire le sélectionner dans une liste M3U autant ne pas y penser (rah zut, j'y ai pensé).

Mais ne voulant pas m'avouer vaincu vu que j'avais lu que les formats et transports présents dans le VLC "ordi" étaient présent dans le VLC "iPad", j'ai bidouillé un petit script PHP pour transformer à la volée le liste de lecture de la friboite (récupérable à http://212.27.40.238/pub/playlist.m3u depuis tout poste interne d'un réseau free).

Grosso modo, le principe du script c'est on lit ligne par ligne le contenu de la playlist, on traite la ligne #EXTINF puis la ligne d'URL (qui commence par rtsp://), tout le reste est ignoré.

L'iPad n'arrive pas à traiter les flux HD donc je les filtre

Voici le script brut de décoffrage, le but étant que ca marche au mépris total de la mise en page et de la présentation.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>Chaines FBX</h1>
<ul>
<?php
$browser
=get_browser($_SERVER["HTTP_USER_AGENT"],true); 

$m3u=file_get_contents("http://212.27.40.238/pub/playlist.m3u");
$m3ulines=explode("\n",$m3u);

foreach (
$m3ulines as $l) {
    if (
preg_match("/(#EXTINF:)(.*),(.*)\s-\s(.*)/",$l,$res)) {
    
//    echo "EXTINF trouvé<br/>\n" ;
        
$domain=$res[2];
        
$chaine=$res[3];
        
$desc=$res[4];
    } elseif (
preg_match("/(rtsp:\/\/.*)$/",$l)) {
        if ( (
strstr($l,"flavour=hd")) && ($browser["parent"]=="iPad") ) {
            echo 
"<li>[$domain - $chaine$desc</li>";
        } else {
            echo 
"<li>[$domain - $chaine] <a href=\"$l\">$desc</a></li> ";
        }

    }
}

?>
</ul>
</body>
</html>

Voilà, un peu moins de 10 lignes.

Il n'y a plus qu'à pointer Safari sur le lieu où vous avez déposé le fichier

Pour tester, vous pouvez voir le résultat à http://maison.senis.org/~fs/fbx.php.

vendredi 15 janvier 2010

Les temps changent... On se dégeekifie doucement

J'ai retrouvé dans un vieux fichier, mon geekcode de 1996.

1996, c'est loin, alors voyons un peu comment j'ai évolué...

Geekcode 1996

------BEGIN GEEK CODE BLOCK------
Version: 3.1
GMD d- s++: a- C++ UL P++ L+ E W++ N++ o K? w++
O+ M-- V? PS PE Y+ PGP-- t+ 5+ X++ R+> tv- b DI D+
G e++ h! r z+
------END GEEK CODE BLOCK------


Geekcode 2010

------BEGIN GEEK CODE BLOCK------
Version: 3.12
GMD d- s++:+ a C++(+) UL+++ P+++>++ L+++ E--- W+++ N+ o+++++> K w--
O- M-- V- PS PE Y+ PGP+ t+ 5++ X R+> tv- b+ DI+ D+
G++ e++++ h(----) r+++ y+++
------END GEEK CODE BLOCK------

Les changements :

  • Je me suis épaissi (de s++: je suis passé à s++:+)
  • J'ai vieilli (a- à a)
  • Je ne programme plus exceptionnellement en C (C++ à C++(+) )
  • Je ne suis plus que sous Linux (3 plus tout de même ! :) )
  • Je me suis amélioré en Perl (1 plus de +) mais je n'ai plus trop le temps de programmer donc je perds la main (>++)
  • Linux est devenu mon seul système et je le maitrise (L+++)
  • Alors que j'utilisais plutôt Emacs, je suis repassé à l'essentiel : Vi !
  • Je rentre maintenant dans la catégorie Webmaster/Administrateur de dédié
  • Usenet ne devient plus que très largement marginal
  • Dans l'intervalle, je n'ai pas été Steve Kinzler, mais l'administrateur/grand prêtre du Grand Oracle Francophone (fr.rec.oracle) mais j'ai arrêté il y a déjà quelques années, le forum est mort désormais...
  • Pour Windows, c'est persona non grata, point barre
  • OS/2, ca existe encore ? et VMS ? ;)
  • Apple me sort désormais autant par les yeux que Microsoft; la faute principalement aux énormes erreurs stratégiques de iPhone (ouverture et multitâche)
  • J'utilise désormais des signatures et le cryptage en cas de besoin
  • Je suis complètement revenu de X-files, ils ont trop tiré sur la corde...
  • Je continue à me désengager du jeu de rôle
  • Maintenant, j'ai appris à apprécier Dilbert et je le lis tous les jours
  • Je continue à apprécier le Geekcode même si il est un peu suranné...
  • Depuis 96, j'ai eu mon doctorat en médecine
  • Pour le logement c'est plus compliqué, je reste un geek de base mais simultanément, je suis marié avec enfant... (d'où le r+++ et z+++ :) ) comme quoi...

Allez, on verra dans 10 ans...

samedi 12 décembre 2009

Les petits clics c'est pas automatique

Je viens de recevoir dans mon courrier pro une série de fiches de synthèse envoyées par HAS sur les principaux examens radiologiques souvent faits à titre systématiques.

J'étais heureux de voir que dans ma pratique courante, je colle déjà bien à ces recommandations... petite gloire personnelle.

Cependant, j'aurais bien deux regrets :

- il manque un feuillet à mon avis pertinent sur l'inutilité très fréquente de la radiographie de genou.

Dans bien des cas, l'examen de choix est plutôt l'IRM ou par défaut le scanner ou l'arthroscanner. Toutes les "entorses" a fortiori sans baillement articulaire, contusions et suite de chutes simples (ou la personne marche en boitant en arrivant) n'ont aucun intérêt d'avoir une RX qui va au mieux faussement rassurer les patients de l'absence de lésion osseuse et passant totalement sous silence les lésions des tissus mous (principalement ménisques et ligaments).

Ma conduite personnelle est, après examen clinique évocateur :

  • radiographie de genou sur les doutes de fracture de rotule : on voit bien, c'est rapide et peu irradiant
  • pour tous les autres traumatismes à forte énergie avec suspicion de fracture : scanner
  • pour toutes les "entorses", atteintes ligamentaires et contusions sans impotance fonctionnelle totale : pas de radiographie, attelle de genou et IRM dans la semaine qui suit soit en systématique si l'examen clinique fait suspecter une rupture ligamentaire ou une atteinte méniscale, soit en cas de persistence dans les autres cas (pour justement ne pas négliger ces étiologies).

Outre l'oubli de l'enterrement de cet examen, l'autre point que je regrette est l'absence de relais vers les patients :

Pour les antibiotiques, on a des pubs (plus ou moins adaptées) très régulièrement qui soutiennent par l'éducation des patients l'effort similaire des médecins. Pour les génériques, idem, il n'est pas un jour sans qu'on en entende parler dans les médias, des règles de remboursement différentes sont mises en place pour les favoriser etc. Là, aucune aide à l'éducation du patient qui pourtant depuis des dizaines d'années à la suite de la scientifisation de la médecine et de l'augmentation de sa technicité pronait le diagnostic précis (et qu'y a t'il de plus précis à l'oeil du profane que de voir la lésion...). De plus tous nous avons (et les patients aussi) des histoires de chasse d'explorations radiographiques non faites en toute bonne foi puis faites par un médecin plus complaisant et qui au final retrouve une lésion à prendre en charge.

Dernière en date : Trauma cranien chez un enfant, transféré au CHU par les pompiers, selon le protocole, surveillance pas de scanner d'emblée et sortie le lendemain. Une semaine après, il persiste une légère céphalée et un hématome pariétal, le médecin traitant prescrit une radiographie du crâne (???) qui au final retrouve une fracture longitudinale du pariétal qui découle sur un scanner qui retrouve un sous-dural... et... rien... à 10 jours, on se contente de toute façon d'une surveillance clinique. Au final toute cette irradiation n'a permis que de faire de jolies images sans aucun gain en terme de santé. Mais la famille du patient était bien remontée contre le CHU...

De mon point de vue, il faut un relais vers les patients pour rendre crédible l'inutilité de ces explorations car indubitablement il y a une demande forte d'imagerie de leur part.

samedi 21 novembre 2009

Tu grippes, je grippe, on se vaccine ?

Pas de réponse définitive ici bas, mais juste un lien pertinent sur un nouvel article brillant de Dominique -Atoute- Dupagne pour vous aider à prendre votre décision : Faut-il ou non se faire vacciner contre la grippe ?

Vous y trouverez tout ce que tant le ministère que les relais médiatiques ne disent pas et masquent souvent par un excès d'émotionnel voire de sensationel.

Vous pourrez compléter par la lecture de l'ensemble de la rubrique A/H1N1 d'Atoute.

Bonne lecture en ce week-end pluvieux.

mardi 21 avril 2009

Musique pourrie, vaudrait mieux amputer les majors !

J'en ai raz-le-bol. (je suis dans ma catégorie "Coups de gueule" alors je peux)

J'en ai raz-le-bol que dès que j'allume la radio j'entende de la daube et toujours la même.

Tenez rien qu'hier, nous sommes allés faire un tour dans le centre-ville de Bordeaux : En une heure et demi, j'ai entendu QUATRE fois "Like a Hobo" (Charlie Winston - label : Atmosphériques) : sur RTL2 dans la bagnole, dans la galerie marchande de Mériadeck une fois arrivé sur place, au Virgin Megastore de Gambetta et enfin en remontant dans la voiture !

Et pourtant nulle part on ne s' est éternisé.

Le soir, on regarde la télé. Avant d'aller au dodo, on zappe un coup sur MTV Idol, devinez ! Et re !

Ce matin je vais prendre ma douche, le poste est sur MFM, une radio encore plus planplan que RTL2 et pan ! A peine un pied dans le bac à douche, revoilà le mal rasé au chapeau mou !

Cette chanson n'est pas plus mauvaise que bien d'autres productions actuelles (non, ce n'est pas un compliment) mais vouloir nous la faire bouffer jusqu'à l'écœurement comme ça entraine chez moi un dégoût qui fait que JAMAIS PLUS je ne voudrai l'écouter, elle sera systématiquement zappée et jamais achetée.

Dans le genre encore plus horripilant, j'ai le "fils de" : Vous avez un père (et une mère) ex-star des sixties, vous n'avez aucun talent, mais vous connaissez plein de gens grace à papa alors produisez une daube qu'on a l'impression que c'est papa qui l'a composé sous la douche et faites vous matraquer par votre boîte de prod à grand coup de "la révolution de l'année 2009", "l'incontournable de l'année" et autres accroches fumeuses. Bravo, vous avez réussi à faire croire aux médias que vous étiez incontournable, vous passez en boucle partout et je peux vous garantir le vomissement à la première note ou à la première image de clip

Le pire dans cette histoire c'est que l'interprète n'y est pour rien, ceux qui sont en cause sont les responsables du plan marketing c'est à dire les labels et majors : Incapable de nous fournir de la qualité, ils tentent de nous forcer les conduits auditifs avec leur production pourrie et après pleurent parce qu'on achète pas leurs disques préférant se voiler la face "bouhou c'est la faute aux vilains pirates, vite HADOPI aide nous" (ils nous refont le coup de la K7 audio puis de la K7 vidéo, puis du CD-R, puis du DVD-R etc.).

A la maison, il doit bien y avoir 200-300 CD, en fait j'ai jamais compté. J'ai arrêté d'en acheter ca doit bien faire 10-15 ans quand leur prix est devenu déraisonnable même pour les classiques déjà rentabilisés et les nouveautés au contenu tout pourri.

Mais que personne ne s'y trompe, c'est pas parce que j'achète plus que je ne consomme pas ! Je consomme et reconsomme ce que j'ai déjà (là où est la qualité) et pour le neuf, c'est Jamendo.

Et puis je consomme aussi différemment, hier je me suis fait un bon délire en achetant le Singstar Queen (PS : Monsieur Sony, il manque des incontournables genre "I'm going slightly mad" !) ! Il ne manque plus que le collant moulant, la petite moustache et la micro canne et je remplis Wembley !