Page 1 of 1

[OBSOLETE] Installer une lib avec upip ou autre à partir d'une URL ?

Posted: Wed 21 Apr 2021 09:19
by sensor56
upip est obsolète, il est maintenant remplacé par l'outil MIP (Micropython Install Package)

Sur ESP, si on est sur un réseau connecté au web, il est facile d'installer une librairie à l'aide de upip depuis l'interpréteur, ce qui est très pratique !

Par exemple, on peut faire :

Code: Select all

>>> import upip as pip
>>> pip.install("module")
Les fichiers de la lib sont installés dans un répertoire /lib/ de la carte. C'est tout simplement nickel !

Je me demande par contre si on aurait pas une possibilité aussi simple et facile d'installter une lib à partir d'une url d'un github par exemple (les fichiers de libs /drivers sont souvent sous cette forme) ? avec pip ou un équivalent wget en micropython. çà serait tout simplement très pratique pour installer les libs et maintenir un dépôt de drivers dans lequel on aurait qu'à donner l'url à aller chercher, le tout depuis interpréteur ou code Python.

Il faut probablement regarder du côté de urequest : https://github.com/micropython/micropyt ... /urequests

On devrait pouvoir faire quelque chose comme :

Code: Select all

import requests
url = "https://raw.githubusercontent.com/mchobby/esp8266-upy/master/mcp4725/lib/mcp4725.py"
#just a random link of a dummy file
r = requests.get(url)
#retrieving data from the URL using get method
with open("mcp4725.py", 'wb') as f:
#giving a name and saving it in any required format
#opening the file in write mode
    f.write(r.content) 
#writes the URL contents from the server
Vu ici : https://www.codespeedy.com/how-to-downl ... ng-python/

En mettant tout çà dans une petite fonction install(url) d'un module driver on devrait arriver à quelque chose de pas mal et simple. Et avec un dict, on pourrait même prédéfinir les url pour n'avoir à saisir que le nom de la lib avec install("nomdriver")... çà serait pas mal du tout...

on pourrait même pousser jusqu'à intégrer l'installation des libs utiles d'un code dans le code, avant les imports, en faisant :

Code: Select all

import drivers, os
files=os.listdir('/')
if not "ds18b20.py" in files : drivers.install("ds18b20")
if not "onewire.py" in files : drivers.install("onewire")
#etc...

import ds18b20
import onewire

...

Ce faisant, dans le code lui-même, on installe les librairies utiles sans autre manip' que d'exécuter le code.

Des suggestions autour de ce sujet ? solution existante "clé en main" que je connaitrai pas ? déjà possible avec upip ?

Re: Installer une lib avec upip ou autre à partir d'une URL ?

Posted: Wed 21 Apr 2021 09:34
by sensor56
De façon plus universelle, c'est à dire pouvant fonctionner avec n'importe quelle carte avec wifi ou non, on pourrait aussi faire un petit script Python sur le poste principal qui récupérerai le fichier avec request sur le poste principal et l'enverrai vers la carte avec pyboard.py, l'utilitaire de transfert depuis Python vers carte micropython. (voir en bas de page de https://docs.micropython.org/en/latest/ ... rd.py.html : çà fonctionne nickel, même depuis Jupyter par exemple..., genre pour grapher à la volée dans un notebook des data venant de la carte micropython... mais c'est pas le sujet là)

Et là idem, en faisant un dict, on pourrait très bien n'avoir qu'à faire install("nommodule"), voire install(typecarte,"nommodule") par exemple install(RP2,"ds18b20") et zou, çà va chercher sur l'url prédéfinie et çà pose le fichier de lib sur la carte. C'est une solution 2 qui fonctionnera pour toutes les cartes.

Je reste intéressé de suggestions malgré tout autour du sujet, pour le faire sur les cartes wifi. Et c'est un outil qui se couplerait très bien avec un répertoire de lib à jour.

Re: Installer une lib avec upip ou autre à partir d'une URL ?

Posted: Wed 21 Apr 2021 16:06
by sensor56
Bon, du coup j'ai exploré l'idée "universelle" pour commencer :

- créer un répertoire pour les libs de la carte, un sous-rép du répertoire des codes typiquement
- y placer Pyboard.py
- y placer le code ci-dessous en enregistrant drivers.py

Code: Select all

#!/usr/bin/env python3
# by X.H. - www.micropython.fr - 2021

import requests
import subprocess

# listing des drivers

urls=({
"ds18x20":"https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/ds18x20.py",
"ds18b20":"https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/ds18x20.py",
"ht16k33_matrix":"https://raw.githubusercontent.com/hybotics/Hybotics_Micropython_HT16K33/master/ht16k33_matrix.py",
"lcd_api.py":"https://github.com/dhylands/python_lcd/blob/master/lcd/lcd_api.py",
"machine_i2_lcd":"https://raw.githubusercontent.com/dhylands/python_lcd/master/lcd/machine_i2c_lcd.py",
"onewire": "https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/onewire.py", 
"tm1637":"https://raw.githubusercontent.com/mcauser/micropython-tm1637/master/tm1637.py"
})

# fonctions d'installation :

def install(driverIn, portIn='/dev/ttyUSB0'):

    #-- copie locale du fichier
    #url = "https://raw.githubusercontent.com/mchobby/esp8266-upy/master/mcp4725/lib/mcp4725.py"
    url=urls[driverIn] # url a partir du dict
    filename=url.split('/')[-1] # dernier element est le nom de fichier
    r = requests.get(url)

    with open(filename, 'wb') as f:
        f.write(r.content)     

    print("-> Download  de : " + filename + " depuis : " + url + " OK !")
    
    #-- copie du fichier sur la carte Micropython 
    cmd=['python3', 'pyboard.py', '--device', portIn , '-f', 'cp', filename, ':'+filename, '--no-follow']
    
    p=subprocess.run(cmd)
    
    print("-> Copie de : " + filename + " vers " +  portIn + " OK !")
    
def installed(portIn='/dev/ttyUSB0'):
    import pyboard
    pyb=pyboard.Pyboard('/dev/ttyUSB0', 115200)
    pyb.enter_raw_repl()
    ret=pyb.exec("""import os
print(os.listdir())
""")

    print(ret)

    pyb.exit_raw_repl()
    
def listing():
    
    for item in urls.keys():
        print("- "+item)
Ouvrir un interpréteur Python 3 (système) dans ce répertoire et on peut désormais faire :

Code: Select all

import drivers
drivers.listing() # renvoie liste des drivers disponibles = les clés du dict
drivers.install("onewire") # installe le driver sur la carte depuis internet 
drivers.installed() # renvoie le contenu de la carte 
Le port est USB0 par défaut. Préciser si autre port.
On a les bases d'un installateur de libs à partir de github directement. Il suffit de compléter le dict.
Une amélioration serait de mettre le dict dans un fichier et d'avoir un dict par type de plateforme.
Et même mieux, télécharger le dict à partir d'un fichier dans un dépot maintenu à jour. Un truc qui pourrait être collectivement géré d'ailleurs... liste des drivers validés / testés par plateforme. Déjà les plus courants.
Pour avoir testé, c'est très facile de redéployer les libs sur une carte : drivers.install("ds18b20") et that is it !

Je vais voir si sur l'ESP on peut le faire directement depuis l'interpréteur, ce qui simplifierai encore plus les choses ! Mais le principe fondamental serait le même.

Re: Installer une lib avec upip ou autre à partir d'une URL ?

Posted: Thu 22 Apr 2021 08:03
by sensor56
Un petit complément : une fois ces bases posées, on peut facilement envisager de traiter non pas une url mais un fichier contenant plusieurs url à laide d'une fonction non pas install() mais process() par exemple. Et çà nous ferait une sorte de micro-installateur d'applications "clé en main" : installation du code principal dans main.py + des libs d'un coup +/- fichier d'instruction de câblage. On câble, et zou çà fonctionne. Intéressant pour des tutos, etc.

Du coup l'outil n'est pas spécifique aux drivers, mais est d'usage beaucoup plus large potentiel : drivers, applis, etc. à partir d'url.

Re: Installer une lib avec upip ou autre à partir d'une URL ?

Posted: Thu 22 Apr 2021 09:54
by sensor56
Je viens de tester / faire la version micropython directement utilisable sur un ESP :

Activer le wifi comme usuellement, ou manuellement dans la console en faisant typiquement :

Code: Select all

>>> import network
>>> station=network.WLAN(network.STA_IF)
>>> station.active(True)
True
>>> station.connect("ssid","password")
>>> station.isconnected()
True
>>> station.ifconfig()
('192.168.0.101', '255.255.255.0', '192.168.0.1', '0.0.0.0') 
```
Une fois le wifi actif, installer urequests :

Code: Select all

>>> import upip as pip
>>> pip.install("urequests")
Installing to: /lib/
Warning: micropython.org SSL certificate is not validated
Installing urequests 0.6 from https://micropython.org/pi/urequests/urequests-0.6.tar.gz
Créer le fichier suivant drivers.py et le placer sur la carte :

Code: Select all

#!/usr/bin/env python3
# by X.H. - www.micropython.fr - 2021

import urequests as requests

# listing des drivers

urls=({
"ds18x20":"https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/ds18x20.py",
"ds18b20":"https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/ds18x20.py",
"ht16k33_matrix":"https://raw.githubusercontent.com/hybotics/Hybotics_Micropython_HT16K33/master/ht16k33_matrix.py",
"lcd_api":"https://github.com/dhylands/python_lcd/blob/master/lcd/lcd_api.py",
"machine_i2_lcd":"https://raw.githubusercontent.com/dhylands/python_lcd/master/lcd/machine_i2c_lcd.py",
"onewire": "https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/onewire.py", 
"tm1637":"https://raw.githubusercontent.com/mcauser/micropython-tm1637/master/tm1637.py"
})

# fonctions d'installation :

def install_from_url(urlIn):

    #-- copie locale du fichier
    #url = "https://raw.githubusercontent.com/mchobby/esp8266-upy/master/mcp4725/lib/mcp4725.py"
    url=urlIn
    filename=url.split('/')[-1] # dernier element est le nom de fichier
    r = requests.get(url)

    with open(filename, 'wb') as f:
        f.write(r.content)     

    
    print("Download de : " + filename + " depuis : " + url + " OK !")


def install(driverIn):

    #-- copie locale du fichier et c'est tout !
    #url = "https://raw.githubusercontent.com/mchobby/esp8266-upy/master/mcp4725/lib/mcp4725.py"
    url=urls[driverIn] # url a partir du dict
    filename=url.split('/')[-1] # dernier element est le nom de fichier
    r = requests.get(url)

    with open(filename, 'wb') as f:
        f.write(r.content)     

    print("-> Download  de : " + filename + " depuis : " + url + " OK !")

def install(driverIn):

    #-- copie locale du fichier et c'est tout !
    #url = "https://raw.githubusercontent.com/mchobby/esp8266-upy/master/mcp4725/lib/mcp4725.py"
    url=urls[driverIn] # url a partir du dict
    filename=url.split('/')[-1] # dernier element est le nom de fichier
    r = requests.get(url)

    with open(filename, 'wb') as f:
        f.write(r.content)     

    print("-> Download  de : " + filename + " depuis : " + url + " OK !")
    
def installed():
        import os
        print(os.listdir())
    
def listing():
    
    for item in urls.keys():
        print("- "+item)
Ensuite, ben c'est plus du jeu... on installe n'importe quel drivers présent dans le dict en faisant :

Code: Select all

>>>import drivers
>>>print(dir(drivers))
['__class__', '__name__', '__file__', 'install', 'requests', 'urls', 'install_from_url', 'installed', 'listing']
>>>print(drivers.listing)
<function listing at 0x3ffe5fd0>
>>>print(drivers.listing())
- lcd_api
- machine_i2_lcd
- onewire
- tm1637
- ds18x20
- ds18b20
- ht16k33_matrix

>>>drivers.install('onewire')
-> Download  de : onewire.py depuis : https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/onewire.py OK !
>>>drivers.install('ds18b20')
-> Download  de : ds18x20.py depuis : https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/ds18x20.py OK !
>>>drivers.install_from_url('https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/ds18x20.py')
Download de : ds18x20.py depuis : https://raw.githubusercontent.com/micropython/micropython/master/drivers/onewire/ds18x20.py OK !
Il reste plus qu'à enrichir le dict au fil de ses usages... ou à mettre le dict dans un répertoire. Au final, une sorte de 'upip' minimaliste, capable de taper n'importe quelle url pour installer un fichier directement sur la carte. C'est cool ! Je partage en espérant que çà intéresse, mais moi, je suis très content déjà de faire çà avec micropython.

C'est définitivement cool ce langage sur microcontrôleur, et on voit ici une fois de plus qu'on a clairement les caractéristiques d'un micro-OS plutôt que d'un simple langage.

Re: Installer une lib avec upip ou autre à partir d'une URL ?

Posted: Thu 22 Apr 2021 20:44
by Dominique
C'est très intéressant comme approche :D

Ce qui serait intéressant, c'est d'extraire la liste des URLs/drivers du driver.py pour le stocker dans un fichier séparé drv_urls.py .

Il suffira alors de faire un from drv_urls import urls pour obtenir les données utiles.

Je proposerais également d'avoir une variable version=1 au cas où tu déciderais un jour de modifier la structure de urls .

Re: Installer une lib avec upip ou autre à partir d'une URL ?

Posted: Fri 23 Apr 2021 07:17
by sensor56
eh, mais c'est que tu me ferais presque un compliment là ! :o

oui, je confirme, mettre le dict dans un fichier séparé. Et même faire un dict par plateforme (ESP 32, Pico, etc.) car les libs peuvent ne pas être exactement les mêmes pour toutes les plateformes, avoir une petite modif dans les coins. Pour le moment çà va comme çà... mais dès que çà va grossir, séparer dans un fichier.

et prévoir une fonction load_dict("fichier_platform.py") et/ou définir par défaut dans le drivers.py, ce qui est simple aussi.

J'ai surtout aussi l'intention de faire une fonction process("projet.pkg") avec :

* projet.pkg : un fichier qui contient une série d'URL successives des fichiers du projet de la forme :

Code: Select all

driver : ds18b20
driver : machine_i2c_lcd
driver: lcd_api
url : http://url_projet/fichier.py
url : http://url_projet/fichier2.py
url : http://url_projet/fichier3.py
url_main : http://url_projet/main.py
* process() la fonction qui installe tous les drivers et les urls du fichier projet.pkg en se basant soit sur la fonction intall() soit sur la fonction intall_from_url() précédentes. le fichier url_main serait enregistré en main.py même si il ne s'appelle pas main.py.

En un coup, on a l'installation de tous les fichiers d'un tuto, d'un projet, etc. C'est personnalisable facilement à souhait et on peut taper les fichiers sur un dépot github/gitlab, etc. C'est vraiment pas mal. Pour redéployer sur une nouvelle carte, ou à distance, etc.

Et cerise sur le gâteau, la fonction process pourrait elle-même aller chercher le fichier *.pkg sur une url... on aurait là une sorte de micro-gestionnaire de paquets plutôt simple mais aussi très efficace. Tu fais un projet bidule avec pleins de lib, fichiers, etc. et t'as juste à dire : faîtes process(url_projet/projet.pkg)... et zou, tout est sur la carte... juste à câbler et çà fonctionne.

Et des corrections / évolutions d'un projet serait du coup facile à répercuter : on refait juste process(url_projet/projet.pkg)

Prévoir peut-être aussi que si des fichiers de même nom existent déjà quand on fait une install ou un process, on les garde en changeant le nom en ajoutant un .bak classique.

Ah là là... mais pourquoi les choses sont si simples en Micropython !!? :D

Re: Installer une lib avec upip ou autre à partir d'une URL ?

Posted: Fri 23 Apr 2021 21:22
by Dominique
Quand l'idée est bonne... et bien elle est bonne.
La récupération et installation des dépendances pilotes reste un vrai problème!
Une petite solution simple, efficace et robuste serait la bienvenue.
Utiliser un script python c'est quand même mieux qu'un script bootstrap.sh (comme j'ai fais pour les projets de la maison pythonic)

Par contre, je suis réservé pour le format pkg....
J'aurais tendance a privilégier une structure python pour les données... suffit de faire un import du fichier pour s'assurer qu'il est au bon format.
Et aussi parce cela revient quand même un peu a un dépôt pip (pip install) ou git (git clone)... cela ne ferait-il pas doublons?

Re: Installer une lib avec upip ou autre à partir d'une URL ?

Posted: Sat 24 Apr 2021 09:02
by sensor56
Bonnes remarques.

Oui, le format du *.pkg peut être du dict, de la list... c'est pas un problème au format *.py. On ferai juste un import.

Pour pip, oui, c'est idem, en plus simple. Et tu peux taper sur les url que tu veux, pas forcément pypi...

Pour git, je n'ai pas connaissance qu'on puisse taper des url différentes, seulement un dépôt entier. Si le dépot est consistant, çà revient au même, mais si tu suis des urls, tu peux bénéficier des mises à jours des urls en question aussi.

Enfin, je ne dirai pas doublon, mais complémentaire. A voir à l'usage... mais vu le temps que çà a pris à faire / tester, le risque de l'inutilité n'est pas très grand...

Je n'ai pas connaissance sinon d'un module git en micropython : çà existe ? tu peux cloner le dépôt directement sur l'ESP ?
En CPython, y'a çà : https://github.com/gitpython-developers/GitPython mais à mon avis c'est bien trop gros git pour être faisable sur micropython (versionning etc. )

Là ce qui est intéressant, c'est qu'on peut vraiment faire du "chirurgical" sur un projet / tutos : on vient chercher juste les URL précises utiles : genre un fichier précis d'un dépôt beaucoup plus large. Les objections sont utiles et intéressantes pour cerner l'intérêt de l'idée, mais plus j'y pense, et plus je trouve que çà a du sens.

Sinon, tu dis script sh mais tu peux pas le faire directement sur la carte çà ? là, je parle d'un truc qui peut directement se charger depuis la carte ESP wifi si on l'a (sinon, oui, avec la version CPython, on fait copie sur le pc et on envoie à la carte).