Sending SMS with HiLink API¶
HiLink API is available for some of 3G/LTE modems and routers.
This is example of how it was used on a particular modem, for other devices it will work differently.
Some of the error API endpoints returns:
100002 – SYSTEM NO SUPPORT
100003 – SYSTEM NO RIGHTS
100004 – SYSTEM BUSY
108001 – LOGIN USERNAME WRONG
108002 – LOGIN PASSWORD WRONG
108003 – LOGIN ALREADY LOGIN
108006 – LOGIN USERNAME PWD WRONG
108007 – LOGIN USERNAME PWD ORERRUN
120001 – VOICE BUSY
125001 – WRONG TOKEN
125002 – WRONG SESSION
125003 – WRONG SESSION TOKEN
import re
%load_ext restmagic
Set device address:
%rest_root http://192.168.8.1
Requests defaults are set.
Start the session. SessionID cookie is required to use device functions:
%rest_session
%rest -q /
New session started.
<Response [200]>
Get the config:
r = %rest -q /config/global/config.xml
re.findall(r'^.*login.*$', r.text, re.MULTILINE)
[u'<login>1</login>']
login == 1
means that login is required to use device functions.
Auth token is required to login, let’s get that token first:
r = %rest -v /api/webserver/SesTokInfo
token = re.search('<TokInfo>(.*)</TokInfo>', r.text).group(1)
print("Token is: " + token)
< GET /api/webserver/SesTokInfo HTTP/1.1
< Host: 192.168.8.1
< Connection: keep-alive
< Accept-Encoding: gzip, deflate
< Accept: */*
< User-Agent: python-requests/2.19.1
< Cookie: SessionID=1OCMw61lUAc+N8Eiw6DhoD2jYp7y9jy05SLKoiH3m2UfjxWXMCa7+uVRhO3xmJhKe6Ito+m23ofB4Aaj7ORcQZOxzh3trp+VYjSCyStmC9AwYDK/gbtyrKVilRjgj1Hv
<
> HTTP/1.1 200 OK
> Date: Thu, 01 Jan 1970 00:00:00 GMT
> Server: mini_httpd/1.19 19dec2003
> Connection: keep-alive
> Keep-Alive: timeout=10, max=100
> X-Download-Options: noopen
> X-Frame-Options: deny
> X-XSS-Protection: 1; mode=block
> Strict-Transport-Security: max-age=31536000; includeSubdomains
> Cache-Control: no-cache
> Content-Type: text/html
> Content-Length: 277
>
<?xml version="1.0" encoding="UTF-8"?>
<response>
<SesInfo>SessionID=1OCMw61lUAc+N8Eiw6DhoD2jYp7y9jy05SLKoiH3m2UfjxWXMCa7+uVRhO3xmJhKe6Ito+m23ofB4Aaj7ORcQZOxzh3trp+VYjSCyStmC9AwYDK/gbtyrKVilRjgj1Hv</SesInfo>
<TokInfo>cXVEAoE1PKWAevq7XvupGewKDEieagYJ</TokInfo>
</response>
Token is: cXVEAoE1PKWAevq7XvupGewKDEieagYJ
Login state check:
%rest -v /api/user/state-login
< GET /api/user/state-login HTTP/1.1
< Host: 192.168.8.1
< Connection: keep-alive
< Accept-Encoding: gzip, deflate
< Accept: */*
< User-Agent: python-requests/2.19.1
< Cookie: SessionID=1OCMw61lUAc+N8Eiw6DhoD2jYp7y9jy05SLKoiH3m2UfjxWXMCa7+uVRhO3xmJhKe6Ito+m23ofB4Aaj7ORcQZOxzh3trp+VYjSCyStmC9AwYDK/gbtyrKVilRjgj1Hv
<
> HTTP/1.1 200 OK
> Date: Thu, 01 Jan 1970 00:00:00 GMT
> Server: mini_httpd/1.19 19dec2003
> Connection: keep-alive
> Keep-Alive: timeout=10, max=100
> X-Download-Options: noopen
> X-Frame-Options: deny
> X-XSS-Protection: 1; mode=block
> Strict-Transport-Security: max-age=31536000; includeSubdomains
> Cache-Control: no-cache
> Content-Type: text/html
> Content-Length: 146
>
<?xml version="1.0" encoding="UTF-8"?>
<response>
<State>-1</State>
<Username>admin</Username>
<password_type>4</password_type>
</response>
<Response [200]>
password_type
== 4 means password should be encoded in a weird way
import hashlib
from base64 import b64encode
from binascii import hexlify
def sha256(data):
return hexlify(hashlib.sha256(data).digest())
def encode_password(name, raw_password, token):
return b64encode(sha256(
name + b64encode(sha256(raw_password)) + token
))
username = 'admin'
raw_password = 'admin'
password = encode_password(username, raw_password, token)
password
'MDg3Yjk2OTlmMGFmZDY2ZjZiYTg3OWRlZGY0ZGJlZWM4N2FkNWYzY2RhYmIyYjNmOWQ1NmRjZjc1ZTVjMDU4NA=='
SessionID is stored in cookie, Token in__RequestVerificationToken
header, login and password in form fields.
Ready to login:
%%rest -v POST /api/user/login
__RequestVerificationToken: $token
<?xml version: "1.0" encoding="UTF-8"?>
<request>
<Username>${username}</Username>
<Password>${password}</Password>
<password_type>4</password_type>
</request>
< POST /api/user/login HTTP/1.1
< Host: 192.168.8.1
< Connection: keep-alive
< Accept-Encoding: gzip, deflate
< Accept: */*
< User-Agent: python-requests/2.19.1
< __RequestVerificationToken: cXVEAoE1PKWAevq7XvupGewKDEieagYJ
< Cookie: SessionID=1OCMw61lUAc+N8Eiw6DhoD2jYp7y9jy05SLKoiH3m2UfjxWXMCa7+uVRhO3xmJhKe6Ito+m23ofB4Aaj7ORcQZOxzh3trp+VYjSCyStmC9AwYDK/gbtyrKVilRjgj1Hv
< Content-Length: 262
<
< <?xml version: "1.0" encoding="UTF-8"?>
<request>
<Username>admin</Username>
<Password>MDg3Yjk2OTlmMGFmZDY2ZjZiYTg3OWRlZGY0ZGJlZWM4N2FkNWYzY2RhYmIyYjNmOWQ1NmRjZjc1ZTVjMDU4NA==</Password>
<password_type>4</password_type>
</request>
> HTTP/1.1 200 OK
> Date: Thu, 01 Jan 1970 00:00:00 GMT
> Server: mini_httpd/1.19 19dec2003
> Connection: close
> X-Download-Options: noopen
> X-Frame-Options: deny
> X-XSS-Protection: 1; mode=block
> Strict-Transport-Security: max-age=31536000; includeSubdomains
> Cache-Control: no-cache
> Content-Type: text/html
> Content-Length: 61
> __RequestVerificationTokenone: hg5BM6tps+th5Izq6WDLglLzb0NSRKMh
> __RequestVerificationTokentwo: 1JZqnOWj3dC6pp+9YB/ncOCJbJXGvpi7
> __RequestVerificationToken: hg5BM6tps+th5Izq6WDLglLzb0NSRKMh#1JZqnOWj3dC6pp+9YB/ncOCJbJXGvpi7#DQufJyl4wgrGuEQNWmYM8mybypbiKY7g#nrDUvDqHRN+Fs+J+/487ZJbFYZdXMMvk#mrO5AGBmaT6q8M80ZHbLwsF11KEkgGdh#mGQ4eVNVF58yrCQB/a5cyyjqj0AXPdvL#qF28d0Mr4QmxHBbmIc2eYetdiW2NBJFl#pAw9tFNrGdL+k6gmg3Lp4jXeYFPcjcSc#7PGbHrb/kb+LL3BW48TxOsITURgfmt9l#0aaUlDksNku0pWqTYzkbeRnzNQJRsMqz#aENIosKeSTVC3cb89pEg/eVuA8H5h5ZH#YDrs55QSOmPjqc8GRp40t8pmd91JxVxH#GAUAhymo++ADCdl8JVdhOs+HbSQKlFAq#j1iNIqDMboby541Qo3AD9hGIm9vsOXQi#w2heSjgwrNkmaK8GC6U0SF2EVOtyWmLl#9IgCqd8b6PaIac3gxfRrcTJ44maCWcWm#JYib/4oA6MLMLRcUYAVqmYF5AxkJNev3#42a69lbLqT6tU3I5L2HZJyW0tdrhCXYc#/1NWh7e30aKr4xbB3iYEZ8mVKL61IyiK#L/wAKNJOlby/s5F2OefWxwn84/HkLabS#i1bjbub11S1HSeOx/yZThO6isduMjx0o#/85UG65so+49Fz32rWK30G2iKsBidW0Q#2CugWs/KKoKmHXHXjOhY4fzUS1N6yus8#keMr8u/phCa3Q2hRBDJpMbbEpex/05w1#qVoIa5aDThmvZO+SU8oepHFKGTacOokH#CtxWL9LRAUZ2c8DmGc+iIcMaTQvV3uzf#m1R++8ngoAeigdJiDM59dmZ0nf3RNhz1#7h+vC2HrpL0RO13mbY1QfISOG/8e6K9D#JHq2REF+apigGGCVOZ1VpEBftt4Ni6QU#SjIimGQFJmiubdb5D8R7pORrkEB2dY4q#ZkTwMIfDnmQdI+Z6/tequCSpFJMSlUlV#1fIL+GD9mU6wzGrjsEpn1U8j8RS2VoKY#
> Set-Cookie: SessionID=f7es/vn9NPRJ0ju5eGs7DBiCjiHZQFPTYsoMt9UQCjurky5TP3G+i0LywRaMZ3KG5TFFrQcciILIX3/XuL168NgvYf99xeN8exyxG0ODQBZGXudrjr2wk6tX+oEeeO2w;path =/;HttpOnly;
>
<?xml version="1.0" encoding="UTF-8"?><response>OK</response>
<Response [200]>
r = _
Login endpoint returns a a bunch of tokens to use:
r.headers['__RequestVerificationToken']
'hg5BM6tps+th5Izq6WDLglLzb0NSRKMh#1JZqnOWj3dC6pp+9YB/ncOCJbJXGvpi7#DQufJyl4wgrGuEQNWmYM8mybypbiKY7g#nrDUvDqHRN+Fs+J+/487ZJbFYZdXMMvk#mrO5AGBmaT6q8M80ZHbLwsF11KEkgGdh#mGQ4eVNVF58yrCQB/a5cyyjqj0AXPdvL#qF28d0Mr4QmxHBbmIc2eYetdiW2NBJFl#pAw9tFNrGdL+k6gmg3Lp4jXeYFPcjcSc#7PGbHrb/kb+LL3BW48TxOsITURgfmt9l#0aaUlDksNku0pWqTYzkbeRnzNQJRsMqz#aENIosKeSTVC3cb89pEg/eVuA8H5h5ZH#YDrs55QSOmPjqc8GRp40t8pmd91JxVxH#GAUAhymo++ADCdl8JVdhOs+HbSQKlFAq#j1iNIqDMboby541Qo3AD9hGIm9vsOXQi#w2heSjgwrNkmaK8GC6U0SF2EVOtyWmLl#9IgCqd8b6PaIac3gxfRrcTJ44maCWcWm#JYib/4oA6MLMLRcUYAVqmYF5AxkJNev3#42a69lbLqT6tU3I5L2HZJyW0tdrhCXYc#/1NWh7e30aKr4xbB3iYEZ8mVKL61IyiK#L/wAKNJOlby/s5F2OefWxwn84/HkLabS#i1bjbub11S1HSeOx/yZThO6isduMjx0o#/85UG65so+49Fz32rWK30G2iKsBidW0Q#2CugWs/KKoKmHXHXjOhY4fzUS1N6yus8#keMr8u/phCa3Q2hRBDJpMbbEpex/05w1#qVoIa5aDThmvZO+SU8oepHFKGTacOokH#CtxWL9LRAUZ2c8DmGc+iIcMaTQvV3uzf#m1R++8ngoAeigdJiDM59dmZ0nf3RNhz1#7h+vC2HrpL0RO13mbY1QfISOG/8e6K9D#JHq2REF+apigGGCVOZ1VpEBftt4Ni6QU#SjIimGQFJmiubdb5D8R7pORrkEB2dY4q#ZkTwMIfDnmQdI+Z6/tequCSpFJMSlUlV#1fIL+GD9mU6wzGrjsEpn1U8j8RS2VoKY#'
Each API call require a new token:
tokens = (t for t in filter(None, r.headers['__RequestVerificationToken'].split('#')))
token = tokens.next()
print("Next token is: " + token)
Next token is: hg5BM6tps+th5Izq6WDLglLzb0NSRKMh
friend_phone = '' # random phone number here
%%rest POST /api/sms/send-sms
__RequestVerificationToken: $token
<?xml version='1.0' encoding='UTF-8'?>
<request>
<Index>-1</Index>
<Phones><Phone>${friend_phone}</Phone></Phones>
<Sca></Sca>
<Content>Hello? Is there anybody in there?</Content>
<Length>-1</Length>
<Reserved>1</Reserved>
<Date>-1</Date>
</request>
<Response [200]>
SMS was sended, let’s try to send more
%%rest POST /api/sms/send-sms
__RequestVerificationToken: $token
<?xml version='1.0' encoding='UTF-8'?>
<request>
<Index>-1</Index>
<Phones><Phone>${friend_phone}</Phone></Phones>
<Sca></Sca>
<Content>Just nod if you can hear me.</Content>
<Length>-1</Length>
<Reserved>1</Reserved>
<Date>-1</Date>
</request>
125003
<Response [200]>
125003
error returned - SMS is not sended, need to use the next token:
token = tokens.next()
print("Next token is: " + token)
Next token is: 1JZqnOWj3dC6pp+9YB/ncOCJbJXGvpi7
%%rest POST /api/sms/send-sms
__RequestVerificationToken: $token
<?xml version='1.0' encoding='UTF-8'?>
<request>
<Index>-1</Index>
<Phones><Phone>${friend_phone}</Phone></Phones>
<Sca></Sca>
<Content>Is there anyone at home?</Content>
<Length>-1</Length>
<Reserved>1</Reserved>
<Date>-1</Date>
</request>
<Response [200]>