『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 41970|回复: 38

[经验分享] 功能近乎完美的短信网关解决方案:树莓派+上网卡+MQTT

[复制链接]

105

主题

2954

帖子

1万

积分

超级版主

智能家居&单板滑雪痴迷爱好者

Rank: 8Rank: 8

积分
12103
金钱
9084
HASS币
460

教程狂人突出贡献

发表于 2020-5-18 12:04:23 | 显示全部楼层 |阅读模式
本帖最后由 XCray 于 2021-8-5 06:57 编辑

20210619注:新版本(大概从0.110左右开始)加入的“SMS notifications via GSM-modem”已经可以很好的解决短信收发问题,用的也是gammu,所以本贴所述的方法也就不需要了。
20210805注:2021.7.x-2021.8.x版本下““SMS notifications via GSM-modem”组件无法正常工作,使得本贴方法又有了必要性。
0. 背景
群晖docker上跑hassio,NanoPi R2S作主路由(跑mqtt broker)、树莓派跑monitor(一个非常好用的利用低功耗蓝牙检测手机在家的脚本)。
之前把3G上网卡插在群晖上,供hassio发送短信通知用。这个做法虽然稳定简单,但缺点也很明显:
- 不能收短信。
- 启动时要求上网卡必须插好
这个上网卡里的SIM卡有时还需要收个短信啥的,另外,互联网不通的时候,除了告警,短信也是一个很好的控制指令传送通道,不能接收短信的话功能就不完整了。
本着折腾的精神,继续探索更完整、更完美的方案,把树莓派打造成为功能完备的短信网关,有些内容也算自己摸出来的,贴出来供大家参考。

1. 效果
除了之前已经实现的在互联网不通时仍可以用短信发送重大告警消息外,还可以在hass上自动呈现收到的短信、向手机推送短信内容,并且可以通过短信对hass进行远程控制(比如关警戒等)。
ss1.png ss2.png

2. 原理及实现方法
原理很简单,树莓派收到短信后,用mqtt协议通知hass,hass在前端呈现并推送通知到手机(免费)。在警情发生时,hass用mqtt协议请求树莓派发送短信通知。树莓派当然是积极响应这个请求啦啦啦啦~~~~
这里只描述与短信直接相关的内容,其余内容在别的帖子里,有兴趣的话慢慢找吧:-)
这个方案参考了https://post.smzdm.com/p/a4wme8zx/,感谢原作者erickson_et的热心分享。

2.1 上网卡从群晖上取下,插回树莓派上。修改hass配置,去掉sms及相应notify内容。
2.2 树莓派上安装配套软件,gammu、gammu-smsd、python-gammu等

2.3 树莓派上功能配置及程序代码:520这天我把下面的内容高度精简了一番,这下就很清晰了

  - 上网卡插入后/dev下新增3个虚拟串口,ttyUSB0~3,一般都用第一个就行(另有一个是用不了的)。

  - 编辑接收配置文件 sudo vim /etc/gammu-smsdrc,这个文件安装gammu-smsd后就有了,重点是修改这几行:
[gammu]
port = /dev/ttyUSB0
connection = at115200
[smsd]
service = files
RunOnReceive = /usr/bin/python3 /home/pi/smsgw/sms2mqtt.py
logfile = /home/pi/smsgw/log/log_smsd.log

# Paths where messages are stored
inboxpath = /home/pi/smsgw/inbox/
outboxpath = /home/pi/smsgw/outbox/
sentsmspath = /home/pi/smsgw/sent/
errorsmspath = /home/pi/smsgw/error/

- 收到短信后的处理程序,也就是上面说的sms2mqtt.py,我根据自己的需要修改如下(把之前的两个文件合并为一个):
#!/usr/bin/env python
# encoding: utf-8
import os
import sys
import requests
import json
import datetime
import subprocess
import paho.mqtt.publish as publish
# MQTT broker
HOST = "10.0.1.1"
PORT = 1883

if __name__ == "__main__":
  #----------------------获取短信内容----------------------
  numParts = int(os.environ['DECODED_PARTS'])
  text = ''
  #单条短信内容
  if numParts == 0:
    text = os.environ['SMS_1_TEXT']

  #多条短信内容
  else:
    text = os.environ['DECODED_0_TEXT']

  #发件人
  sender = os.environ['SMS_1_NUMBER']
  #接收日期和时间就取当前系统时间
  recTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  #完整转发内容
  smsContent = '发件人:' + sender + '\n时间:' + recTime + '\n\n' + text

  #--------------------转发到MQTT--------------------
  publish.single("smsR", smsContent, qos = 1,hostname=HOST,port=PORT)
推送的topic设置为smsR,可以根据喜好随便改,和hass配合好就行。

  - 接收daemon开机自启动,/lib/systemd/system/gammu-smsd.service,这个文件安装gammu-smsd之后就有了,不用修改,看一眼就行
  - 开机启动,大家应该都知道的,sudo systemctl enable gammu-smsd,启动 start、停止stop等等

到这里,树莓派的功能已经搞好了一半,就是收到短信后通知hass。

那么hass方面呢?当然要配合好才行。hass方面需要做的,就是增加一条自动化:
- id: '1589757859753'
  alias: smsFrMQTT
  description: ''
  trigger:
  - platform: mqtt
    topic: smsR
  condition: []
  action:
  - data_template:
      title: >
        收到短信 {{ now().strftime('%Y-%m-%d %H:%M:%S') }}
      message: "{{ trigger.payload }}"
    service: persistent_notification.create
  - data_template:
      title: 收到短信
      message: "{{ trigger.payload }}"
    service: notify.notify

好了!到这儿工作算是完成一半,接收短信的事情没问题了。
--------------------------------------
剩下的一半更简单,因为前面已经把环境都调通了。

- 首先是hass上设置自动化,把原来的发短信的动作稍微修改一下就行,比如:
  - data:
      payload: 停电了!UPS电池开始放电...
      topic: smsT
    service: mqtt.publish
再比如:
  - data:
      payload: 互联网已断开!
      topic: smsT
    service: mqtt.publish
显然,就是在发生警情的时候,hass用mqtt协议向树莓派发送请求,标题用smsT(当然可以随便改,与树莓派那边匹配就好)。

- 树莓派这边需要另外一个长期运行的进程,监听hass发过来的mqtt消息,并在收到消息后发送短信:
sudo vim /lib/systemd/system/mqtt2smsd.service
[Unit]
Description=daemon for send sms driven by mqtt
[Service]
# Run daemon as root user
ExecReload=/bin/kill -HUP $MAINPID
ExecStopPost=/bin/rm -f /var/run/mqtt2smsd.pid
Type=simple
PIDFile=/var/run/mqtt2smsd.pid
#ExecStartPre=/bin/sleep 30
ExecStart=/usr/bin/python /home/pi/smsgw/mqtt2sms.py --pid /var/run/mqtt2smsd.pid &
[Install]
WantedBy=multi-user.target
- 这个也需要sudo systemctl enable mqtt2smsd.service,然后start一下。。。其中指明的进程代码文件mqtt2sms.py内容如下:
#!/usr/bin/env python
# encoding: utf-8
import paho.mqtt.client as mqtt
import time
import gammu.smsd
import sys

HOST = "10.0.1.1" #自己的mqtt broker
PORT = 1883
receptNum = '18600000000' #自己的电话号码
smsd = gammu.smsd.SMSD('/etc/gammu-smsdrc')
def client_loop():
  client_id = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
  client = mqtt.Client(client_id)    # ClientId不能重复,所以使用当前时间
  client.username_pw_set("", "")  # 必须设置,否则会返回「Connected with result code 4」
  client.on_connect = on_connect
  client.on_message = on_message
  client.connect(HOST, PORT, 60)
  client.loop_forever()

def on_connect(client, userdata, flags, rc):
  # print("Connected with result code "+str(rc))
  client.subscribe("smsT")

def on_message(client, userdata, msg):
  sendContent = msg.payload.decode("utf-8")
  #print(sendContent)
  message = {
     'Text': sendContent,
     'SMSC': {'Location': 1},
     'Number': receptNum,
     'Coding': 'Unicode_No_Compression'
   }
  #print(message)
  smsd.InjectSMS([message])

if __name__ == '__main__':
  client_loop()
   需要强调的是,由于负责短信接收的gammu-smsd已经打开了所配置的虚拟串口/dev/ttyUSB0,这时候再用gammu官网示例代码类似的方法发送短信就不行了,改用注入到smsd才行(或者用另外的端口号比如ttyUSB2或许也行)。

- 回到 /home/pi目录,创建log error inbox outbox sent等子目录,安装依赖软件包pip3 install paho-mqtt,总的来说缺啥补啥就行。

当然,不用树莓派,虚拟机跑debian也完全可以利用本方法实现同样的功能。

好了,就这么多。
——————————————————————————
我把前两天发的帖子精简了一下,这样就更清晰了。
一共有两个python脚本,分别时 mqtt2sms.py 和 sms2mqtt.py ,看名字就知道干啥的了。
创建一个unit文件(/lib/systemd/system/mqtt2smsd.service)、修改一个配置文件(/etc/gammu-smsdrc)
使能、启动两个service项。




评分

参与人数 5金钱 +55 HASS币 +20 收起 理由
sun1451 + 5 论坛有你更精彩!
komoya + 5 膜拜大神!
afanti + 5 感谢楼主分享!
jyz_0501 + 20 论坛有你更精彩!
+ 20 + 20 厉害了word楼主!

查看全部评分

回复

使用道具 举报

105

主题

2954

帖子

1万

积分

超级版主

智能家居&单板滑雪痴迷爱好者

Rank: 8Rank: 8

积分
12103
金钱
9084
HASS币
460

教程狂人突出贡献

 楼主| 发表于 2020-5-19 19:07:18 | 显示全部楼层
jyz_0501 发表于 2020-5-19 10:06
我感觉我的论坛币全用来评分了~~~

感谢加分!顺便讨论哈~
--------------真正的华丽分割线--------------

                               
登录/注册后可看大图

我的偏执——为何非要在智能家居中加入短信功能?
接触智能家居,一开始纯粹为了好玩,就是那种科技感带来的幸福——理工男的本色,改不了
既然是为了好玩,就不会打算花太多钱,所以就上手了小米的套件。。。
后来突然有一天家里进了小偷,虽然手机上有叮的一声提醒,但现在微信短信各种软件推送层出不穷的年代,手机叮一下真的不会引起太大注意。
好在过了几分钟拿起手机看了一眼,嗯???门开啦???再看摄像头——果然有贼!!!
瞬间,肾上腺素飙升!大脑空白了几秒,开始采取行动——两个人一边分头打电话,求助物业+报警,一边穿衣下楼打车往家里奔。。。
感谢小区尽职可靠的物业!在半路上接到物业来电,两个贼,摁住一个。而警察呢???三个小时之后才到达!!!
事后虽然追回了小部分损失,但由于警察的不太尽职和先行的法律,两个小偷,收获很大,却只受到了几个月的轻判——现在的法律,很大程度上真的是在保护坏人!

于是,开始思考智能家居的不足:
1. 提醒力度严重不够。在发生严重的告警事件后,必须有强烈的、独特的提醒才行。而这一点,当时的小米/米家应用做不到。
2. 提醒信息滞后,尤其是摄像头,等我主动看完实况才收到服务器推送的有人移动的告警消息!当然,还是仅仅的叮一声。
3. 可靠性严重不足、尤其是在安防能力方面,无法建立足够的信心。具体就是服务器经常崩溃、告警消息推送经常不够及时、甚至有传感器离线/摄像头离线却没有任何提示的明显漏洞。——我在论坛里嚷了很多次,很久之后,小蚁才增加了摄像头离线告警的功能。
4. 安防能力重大缺失——对断网和断电没有任何应对措施。现在小偷对智能家居的了解恐怕也在加强,而一般的居民楼,入户的电表/电闸和宽带(不管是光纤还是网线)都在楼道里,并且往往裸露在外,很容易就可以断开。试想一下,稍微有些头脑的小偷,应该会有意识在撬门前把光纤/网线剪断、把电闸/保险丝拉开,而这,往往又是轻而易举的!


于是,开始思考改进思路,重点还是安防能力
0. 最最重要的,换一个更不容易被撬的锁
1. 断电断网时必须有应对和及时提醒的能力。
2. 提醒必须足够响亮、独特。
3. 门磁/网关/摄像头等重点部件,必须有电池电量不足、离线的状态监控和告警。
4. 摄像头的记录必须有可靠的多份存储。
于是,不断设计尝试各种补足缺陷补足短板的措施,而这当中的,根据我的思考和实践,短信是一个核心功能
1、可靠。国内的移动通信网络,可靠性是非常高的,而短信又非常成熟,成本也不高。
2、提醒可以响亮、独特。iPhone和部分安卓手机,可以针对特定号码短信单独设置铃音。
。。。。。。。。


                               
登录/注册后可看大图

在整体思路和方案方面,我之前发的另一个帖子说的更多,欢迎大家去围观。
回复

使用道具 举报

105

主题

2954

帖子

1万

积分

超级版主

智能家居&单板滑雪痴迷爱好者

Rank: 8Rank: 8

积分
12103
金钱
9084
HASS币
460

教程狂人突出贡献

 楼主| 发表于 2020-5-18 12:15:29 | 显示全部楼层
本帖最后由 XCray 于 2020-5-18 14:54 编辑

为啥代码块里给我加了那么多的<div>?为啥换行都成了这个样子?Discuz!的编辑功能现在这么跟不上时代啦?————————————————
至于通过短信控制hass(万一在外面、赶上家里网络又断了的情况),只需要在hass上增加自动化条目即可。

可以精确匹配发送指令的电话号码、短信内容,确保不会被别人乱搞给整瞎。

有自虐倾向的话,你甚至可以设计让hass跟你对暗号
回复

使用道具 举报

123

主题

4661

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16410
金钱
11664
HASS币
45
发表于 2020-5-18 12:21:31 | 显示全部楼层
XCray 发表于 2020-5-18 12:15
为啥代码块里给我加了那么多的?为啥换行都成了这个样子?Discuz!的编辑功能现在这么跟不上时代啦? ...

插入时点插入代码,不要点插入引用。

                               
登录/注册后可看大图
回复

使用道具 举报

105

主题

2954

帖子

1万

积分

超级版主

智能家居&单板滑雪痴迷爱好者

Rank: 8Rank: 8

积分
12103
金钱
9084
HASS币
460

教程狂人突出贡献

 楼主| 发表于 2020-5-18 12:28:59 | 显示全部楼层
本帖最后由 XCray 于 2020-6-12 15:19 编辑
囧 发表于 2020-5-18 12:21
插入时点插入代码,不要点插入引用。

引用还好,至少看起来一切正常。代码全是乱的,刚改了一遍,更糟糕,每个都只剩一行了!改成用高级模式,插入代码终于好使了。

感谢置顶设精!

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
悄悄的补充一句:

同样思路,也可以运行于大部分OpenWRT路由器(只要能接上3G/4G上网卡或者模块就行,2G的也行但说不定哪天运营商就把网关了)。

如果有感兴趣的,回帖交流吧。
回复

使用道具 举报

8

主题

690

帖子

4558

积分

论坛元老

Rank: 8Rank: 8

积分
4558
金钱
3863
HASS币
0
QQ
发表于 2020-5-18 12:47:20 | 显示全部楼层
看起来好高端,标记一下
回复

使用道具 举报

105

主题

2954

帖子

1万

积分

超级版主

智能家居&单板滑雪痴迷爱好者

Rank: 8Rank: 8

积分
12103
金钱
9084
HASS币
460

教程狂人突出贡献

 楼主| 发表于 2020-5-19 05:34:45 | 显示全部楼层
囧 发表于 2020-5-18 12:21
插入时点插入代码,不要点插入引用。

感谢加分设精置顶。刚来没几天,请多关照!
回复

使用道具 举报

175

主题

2967

帖子

7606

积分

超级版主

我就是六神

Rank: 8Rank: 8

积分
7606
金钱
4614
HASS币
398

活跃会员教程狂人灌水之王

QQ
发表于 2020-5-19 10:05:58 | 显示全部楼层
这是个大神操作~~~~没看完  但是可以点赞~
回复

使用道具 举报

175

主题

2967

帖子

7606

积分

超级版主

我就是六神

Rank: 8Rank: 8

积分
7606
金钱
4614
HASS币
398

活跃会员教程狂人灌水之王

QQ
发表于 2020-5-19 10:06:50 | 显示全部楼层
囧 发表于 2020-5-18 12:21
插入时点插入代码,不要点插入引用。

我感觉我的论坛币全用来评分了~~~
回复

使用道具 举报

123

主题

4661

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16410
金钱
11664
HASS币
45
发表于 2020-5-19 12:53:05 | 显示全部楼层
jyz_0501 发表于 2020-5-19 10:06
我感觉我的论坛币全用来评分了~~~

你评分不会扣你金币呀~

                               
登录/注册后可看大图

评分

参与人数 1金钱 +4 收起 理由
jyz_0501 + 4 厉害了word楼主!

查看全部评分

回复

使用道具 举报

1

主题

211

帖子

2299

积分

金牌会员

Rank: 6Rank: 6

积分
2299
金钱
2088
HASS币
0
发表于 2020-5-19 14:08:06 | 显示全部楼层
先感谢大神分享,后面慢慢学。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-11-26 07:35 , Processed in 0.573833 second(s), 40 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表