SMS Bot avec TextNow

Salut tout le monde, ici au Canada, il est couteux d’avoir une ligne téléphonique mobile. Les forfaits les plus bas sont dans les 20$ (15 Euro) et ne sont pas illimités. Seulement, le service de TextNow, qui est basiquement en VoIP, permet d’avoir une ligne gratuitement, … via Wifi (Internet).

Avec un mobile, ce n’est pas vraiment intéressant, sauf si tu as déjà un réseau e un accès internet disponible sur le lieux ou tu utilise le téléphone, MAIS, TextNow permet de faire de quoi d’intéressant; un SMS Bot.

Dans mes apprentissages, je me suis donc amusé avec TextNow et Python, car oui, il existe une librairie Python pour TextNow sous Python 3; PyTextNow. ET dans mes essais, j’ai même aidé à fixer un bug.

Le projet n’est plus maintenu car certains aspect légale en découle cause problème et le manque d’intérêt de l’auteur du code de l’améliorer, mais reste totalement fonctionnel.

Noter que j’ai mon propre projet et que je ne garantie pas la disponibilité, mais si vous désirez tester, dans le respect : https://levelkro.net/8707/ pour les détails.

Alors il est possible de coder un robot pour effectuer des tâches, j’en ai configuré un au travail pour me donner des informations sur notre inventaire en cherchant par SKU e un autre pour le divertissement et projets personnel (lien si haut).

Comme dans mon projet, je peut envoyer des images, des sons et des vidéos, je peux aussi le coupler à un autre programme pour par exemple … télécharger de la musique sur Youtube (simplement partager le lien au numéro en SMS et il s’occupe du reste).

Alors il serait simple de l’inclure dans un projet domotique avec Raspberry Pi pour commander à distance et avoir des informations.

Voici mon code, libre a vous de l’éditer, bien sur, et je ne fournis pas le code pour le Youtube, ni mes images :stuck_out_tongue: Allez, codez un peu… au passage, vous avez mon code pour avoir la température avec OpenWheaterMap. (les accents sont volontairement absent, vu qu’il ne prend correctement en charge)

import pytextnow as pytn
import os, sys, getopt, dload, math, time
import configparser, subprocess, json
from unidecode import unidecode
print("Starting bot...")
txtn_user="<USERNAME-TEXTNOW>"
txtn_sid="<SID-TEXTNOW>"
txtn_csrf="<CSRF-TEXTNOW>"
weather_lang="fr"
weather_unit="metric"
weather_apikey="<API-KEY-OPENWEHERMAP>"
client = pytn.Client(txtn_user,sid_cookie=txtn_sid,csrf_cookie=txtn_csrf)
print("Bot started, ready to serve...")

def cleantxt(txt):
    txt=txt.replace("A?","e")
    return txt

def windSpeed(wind):
    speed=math.floor((wind*3600)/1000)
    return str(speed)+"km/h"

def windDirection(deg):
    if(deg >= 0 and deg<= 22):
         wind=" du Nord"
    elif(deg >= 23 and deg<=67):
         wind=" du Nord-Est"
    elif(deg >= 68 and deg<=112):
         wind=" de l'Est"
    elif(deg >= 113 and deg<=157):
         wind=" du Sud-Est"
    elif(deg >= 158 and deg<=202):
         wind=" du Sud"
    elif(deg >= 203 and deg<=247):
         wind=" du Sud-Ouest"
    elif(deg >= 248 and deg<=292):
         wind=" de l'Ouest"
    elif(deg >= 293 and deg<=337):
         wind=" du Nord-Ouest"
    elif(deg >= 338 and deg<=360):
        wind=" du Nord"
    else:
        wind=""
    return wind

@client.on("message")
def on_message(msg):
    if not msg.type == pytn.MESSAGE_TYPE: return
    msgr = msg.content
    msga = msgr.split(" ")
    if ( msga[0].lower() == "ping"):
        msg.send_sms("Pong!")

    elif( msga[0].lower() == "meteo"):
        if( len(msga) <= 1):
            msg.send_sms("Vous n'avez pas indique la region desire.")
            msg.send_sms("Usage: meteo <ville>[,pays]")
        else:
            url = 'http://api.openweathermap.org/data/2.5/weather?q='+msga[1].lower()+'&appid='+weather_apikey+'&lang='+weather_lang+'&units='+weather_unit
            answer = dload.json(url)
            if('message' in answer):
                msg.send_sms("Erreur : "+answer['message'])
            else:
                msg.send_sms(unidecode("Temperature pour "+cleantxt(answer['name'])+" ("+answer['sys']['country']+") - "+cleantxt(answer['weather'][0]['description'])))
                msg.send_sms("Actuellement "+str(answer['main']['temp'])+"'C, min. "+str(answer['main']['temp_min'])+"'C, max. "+str(answer['main']['temp_max'])+"'C, Resenti "+str(answer['main']['feels_like'])+"'C")
                msg.send_sms("Humidite "+str(answer['main']['humidity'])+"%, Vent de "+windSpeed(answer['wind']['speed'])+windDirection(answer['wind']['deg'])+", "+str(answer['clouds']['all'])+"% de nuages")
                if('rain' in answer):
                    msg.send_sms("Averse de "+str(answer['rain']['1h'])+"mm de pluie")
                if('snow' in answer):
                    msg.send_sms("Averse de "+str(answer['snow']['1h'])+"cm de neige")
                
    elif( msga[0].lower() == "prevision" or msga[0].lower() == "forecast"):
        if( len(msga) <= 1):
            msg.send_sms("Vous n'avez pas indique la region desire.")
            msg.send_sms("Usage: forecast <ville>[,pays]")
        else:
            url = 'http://api.openweathermap.org/data/2.5/forecast?q='+msga[1].lower()+'&appid='+weather_apikey+'&lang='+weather_lang+'&units='+weather_unit
            answer = dload.json(url)
            citytime=answer['city']['timezone']
            citytime=str(math.floor(citytime/3600))+"H"
            msg.send_sms(unidecode("Meteo pour "+answer['city']['name']+" ("+answer['city']['country']+", GMT "+citytime+")"))
            i=1;
            for w in answer['list']:
                if i <= 5:
                    if('rain' in answer):
                        rain=", Pluie "+str(answer['rain']['3h'])+"mm"
                    else:
                        rain=""
                    if('snow' in answer):
                        snow=", Neige "+str(answer['snow']['3h'])+"cm"
                    else:
                        snow=""
                    msg.send_sms(w['dt_txt'].replace(":00:00","h (GMT 0H)")+" - "+str(w['main']['temp'])+"'C ("+str(w['main']['feels_like'])+"'C) "+unidecode(w['weather'][0]['description'])+", Min. "+str(w['main']['temp_min'])+"'C, Max. "+str(w['main']['temp_max'])+"'C, Humidite "+str(w['main']['humidity'])+"%, Nuages "+str(w['clouds']['all'])+"%, Vent "+windSpeed(w['wind']['speed'])+windDirection(w['wind']['deg'])+rain+snow)
                    i=i+1
                
    elif( msga[0].lower().find("youtu") != -1):
        config = configparser.ConfigParser()
        config['user']={"number": msg.number.replace("+","")}
        config['video']={"url":msga[0]}
        req=time.time()
        try:
            with open("./yt/"+str(req)+".ini","w") as configfile:
                config.write(configfile)
                msg.send_sms("La video Youtube ("+msga[0]+") a ete mis en liste d'attente. Elle sera envoye des qu'elle sera encoder en audio seulement.")
        except:
            msg.send_sms("Nous n'arrivons pas a mettre la video en liste d'attente, ressayer plus tard.")
            pass
        
    elif( msgr.lower() == "exit 42758"):
        msg.send_sms("Fermeture du robot")
        exit()
        
    elif( msga[0].lower() == "lol" or  msga[0].lower() == "mrbean" or  msga[0].lower() == "bean"):
        msg.send_mms("lol.jpg")
        
    elif( msga[0].lower() == "chien" or msga[0].lower() == "meo"):
        msg.send_mms("chien.mp3")
        
    elif( msga[0].lower() == "bonnefete" or msga[0].lower() == "fete" or msga[0].lower() == "birthday" or msga[0].lower() == "happybirthday"):
        msg.send_mms("bonnefete.mp3")
        
    elif( msga[0].lower() == "ashley" or msga[0].lower() == "rick" or msga[0].lower() == "fart"):
        msg.send_mms("nevergiveyouup.mp4")
        
       
    elif( msga[0].lower() == "apropos" or msga[0].lower() == "about" or msga[0].lower() == "version"):
        msg.send_sms("Python SMS Bot via TextNow. v1.22.5.15-lite - Python3 - © Mathieu Legare <levelkro@yahoo(dot)ca> levelkro(dot).net")
                
    elif( msga[0].lower() == "help" or msga[0].lower() == "aide"):
        msg.send_sms("Les commandes suivantes sont possibles : ")
        msg.send_sms(" Meteo: meteo <cityname>[,countrycode], forecast[prevision] <cityname>[,countrycode]")
        msg.send_sms(" Images, Videos et Sons : bonnefete, lol, ashley")
        msg.send_sms(" Outils : <youtubelink>, ping, send <media> <numero>")
        msg.send_sms("Plus d'informations sur ; levelkro(dot)net/8707/");
        
    else:
        print("Debug : "+msga[0])

SI vous prenez qu’un numéro, vous serez « bloqué » après quelques temps (et devrez le débloquer avec une validation par courriel), je vous conseille fortement d’opter pour l’option de « sécurisation du numéro » qui n’exige pas de texter/appeler au moins une fois par mois pour garder le numéro, de plus, ça évite de ce faire « flag » pour violation des droits d’utilisations. Si vous désirez que le service reste gratuit, éviter de faire du « flood » et des messages de « mass » qui pourrais ou est du Spam. N’oubliez pas que l’abus d’un service fait en sorte que ce service deviendra un jours de plus en plus dur d’accès, alors soyez « soft » dans vos projets.