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

 找回密码
 立即注册
查看: 4331|回复: 29

[教程系列] 看“穷人”如何实现微信控制ha

[复制链接]

12

主题

85

帖子

746

积分

高级会员

Rank: 4

积分
746
金钱
661
HASS币
10
发表于 2023-8-25 12:31:08 | 显示全部楼层 |阅读模式
本帖最后由 KevinYAN 于 2023-8-25 17:31 编辑

更新在开头: 因为下边流程导入碰到问题的朋友比较多,直接在开头放文件:
flows.json (8.19 KB, 下载次数: 31)



   
看到大佬们的微信控制ha, 多数都是需要公网ip,或者找运营商给自家光猫做端口映射。 我自己没有云主机之类的资源。所以一直致力与免费资源。

     在看企业微信的开发者接口文档的时候,惊奇的发现是可以通过客服的历史聊天api获取到微信发送出去的信息的。如果我们通过node red 的http获取到这个信息,那后续的就简单了,只需要对信息分类处理,实现不同的功能即可。

为了较好的实现功能,并处理遇到的问题,建议阅读:
                  发送消息 - 文档 - 企业微信开发者中心 (qq.com)
                 https://developer.work.weixin.qq.com/devtool/query                --错误代码含义查询


获取消息接口:
[color=rgba(14, 19, 26, 0.8)]https://qyapi.weixin.qq.com/cgi-bin/kf/sync_msg?access_token=ACCESS_TOKEN
[color=rgba(14, 19, 26, 0.8)]发送消息接口:
[color=rgba(14, 19, 26, 0.8)]https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=ACCESS_TOKEN

     不过这个发送接口有一点限制,就是从微信发给客服的最后一条消息时间算起,48小时内,客服只能对该微信号推送5条消息。如果你一直发,他也一直回,基本是没什么问题的。不通5条消息推送也勉强够用,如果不够,就再加一个客服人员,重新推送失败的消息(我目前正是这么做的)。

    简单说下过程吧:

微信对话开放平台 (qq.com)  平台创建一个机器人,得到如下核心信息:
微信对话开放平台湖区核心信息.png

登陆自己的企业微信,点开“微信客服”
企业微信客服应用.png
配置事件接收器.png
配置信息写入.png
这里将第一张图获取的三个信息依次填入。

然后我们创建一个客服,我图中创建了,比如图中的“智能家居助手”
创建客服.png

创建完成以后,在页面拉到最下边,点击“企业内部开发",进去后,把自己刚才创建的客服勾选上。

                               
登录/注册后可看大图


企业内部开发.png

到这里,我们基本就搞完了。
---------------------------------


然后就是node red里如何调用的问题了,且看我表演哈。


获取聊天记录流程.png
我的实现也算比较简单,简单来说,就是通过接收消息接口,每7s去抓一下聊天记录,提取到新消息,然后一条一条的发送到后续流程,进行处理。

替换内容:

第一个替换:
get token节点里两个信息 https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=你自己的企业id&corpsecret=微信客服secret ID

企业id查看:
企业id查看.png
企业客服secret查看:
secret查看.png


第二个替换:

重组节点.png
替换自己创建的客服名称就好。  我这里好像也没起作用,每次把三个客服的都提取来了。大家自己测试看看。


-------------------------------------------------------------------------------------------------------------------------

到这里,我想,你的nore red 应该就提取到消息了:
给你看看我的:
发送消息.jpg
发送测试.png



流程代码如下:
[{"id":"8d804279b89c99e1","type":"comment","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"企业微信接收","info":"","x":130,"y":80,"wires":[]},{"id":"8668ae0b458677c4","type":"ping","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","protocol":"Automatic","mode":"timed","name":"网络检查","host":"www.baidu.com","timer":"10","inputs":0,"x":280,"y":80,"wires":[["bdbfe4571da8ccc0","91340d568ce17d1a"]]},{"id":"bdbfe4571da8ccc0","type":"function","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"公布网络状态","func":"if (msg.payload > 0){\n    flow.set("net_stat", true);\n}else{\n    flow.set("net_stat", false);\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":500,"y":80,"wires":[[]]},{"id":"91340d568ce17d1a","type":"function","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"网络恢复触发","func":"\nif (msg.payload > 0) { \n    var current_stat = 1; \n}else {\n    var current_stat = 0; \n}\n\nlet before_state = flow.get("before_state")||0;\n\nflow.set("before_state", current_stat);\n\nif(current_stat != before_state && current_stat == 1){\n    return msg;\n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":500,"y":120,"wires":[["b34f95a58b4b4456"]]},{"id":"aebf9ee5715ea349","type":"function","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"网络检查","func":"if (flow.get("net_stat"))  {\n    return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":160,"wires":[["b34f95a58b4b4456"]]},{"id":"75d6bdc456788532","type":"inject","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"1c/h","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"3600","crontab":"","once":true,"onceDelay":"3","topic":"","payload":"","payloadType":"date","x":130,"y":160,"wires":[["aebf9ee5715ea349"]]},{"id":"60c45160b6c238c9","type":"inject","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"7s/c","props":[],"repeat":"7","crontab":"","once":true,"onceDelay":"5","topic":"","x":130,"y":260,"wires":[["d3edb2c873e3fd0f"]]},{"id":"d3edb2c873e3fd0f","type":"function","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"网络检查","func":"if (flow.get("net_stat"))  {\n    return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":260,"wires":[["6f66aa170a6832e3"]]},{"id":"6f66aa170a6832e3","type":"function","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"重组","func":"msg = {\n    "cursor": flow.get("next_cursor") || null,\n    "limit": 1,\n    "voice_format": 1,\n    "open_kfid": "替换哦",\n    "url": flow.get("sync_kf_url")\n}\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":260,"wires":[["a5b6e9f8d5eb2fb1"]]},{"id":"a5b6e9f8d5eb2fb1","type":"http request","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"获取聊天记录","method":"POST","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":560,"y":260,"wires":[["0860a880482e2d49"]]},{"id":"b34f95a58b4b4456","type":"http request","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"get token","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=替换哦&corpsecret=替换哦","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":720,"y":160,"wires":[["61fdd78716dcc5ce"]]},{"id":"0860a880482e2d49","type":"function","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"提取新消息","func":"if (msg.payload.errcode === 0){           //正确抓到聊天记录再处理\n    //弹出本次最后一个结果\n    var yuan = msg.payload.msg_list;\n    var end = yuan.pop();\n\n    flow.set("next_cursor",msg.payload.next_cursor);\n\n    //获取上次最后一条消息发送时间为本次消息的开始时间,用来获取新消息\n    var start_message_send_time = flow.get("last_message_send_time");\n\n    //存储本次最有一个结果的发送时间为最后一条消息的发送时间\n    flow.set("last_message_send_time", end.send_time);\n\n    msg = {};\n    msg.payload=[];\n    if (end.send_time > start_message_send_time) {\n        msg.payload.push(end);\n\n        end = yuan.pop();\n        while (end.send_time > start_message_send_time) {\n            msg.payload.push(end);\n            end = yuan.pop();\n        }\n    } else {\n        var bs = 1;\n    };\n\n    if( bs != 1){\n        msg.payload = msg.payload.reverse();\n        return msg;\n    };\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":730,"y":260,"wires":[["e794c4c52e2a85a3"]]},{"id":"61fdd78716dcc5ce","type":"function","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"发布url","func":"var url = "https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=" + msg.payload.access_token\nflow.set("send_kf_url",url);\nurl = "https://qyapi.weixin.qq.com/cgi-bin/kf/sync_msg?access_token=" + msg.payload.access_token\nflow.set("sync_kf_url",url);\nurl = "https://qyapi.weixin.qq.com/cgi-bin/kf/service_state/get?access_token=" + msg.payload.access_token\nflow.set("sync_kf_hhzt_url", url);","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":160,"wires":[[]]},{"id":"e794c4c52e2a85a3","type":"split","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"拆分","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":true,"addname":"payload","x":870,"y":260,"wires":[["8e3ee4164e88172e","b7142ca9b1192be7"]]},{"id":"8e3ee4164e88172e","type":"delay","z":"4e296426d7d6e14e","g":"a5f79719cb30e595","name":"","pauseType":"rate","timeout":"8","timeoutUnits":"seconds","rate":"1","nbRateUnits":"0.1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1010,"y":260,"wires":[["e6e641da7489c2c1"]]}]



有了上述的基础以后,我想后续的你应该可以搞定,

比如,输入一个文本,然后处理这个文本,处理完,然后再调用上边提到的发送接口,将处理结果做一个反馈。就想我微信聊天截图里,有发送,有反馈。

这里就送大家两张图吧,上边的信息已经够庞大的了,先消化休息休息。

发送消息.png

必要信息.png
这里客服id和外部用户id ,都是上边流程里接收到的信息所包含的。自己debug跟踪一下,就能看到。 每个微信客户,对应一个外部客户id.
标准推送参数.png
标准化推送信息后,直接抛到推送接口
推送.png
这里推送是个空的,因为他的url来自于前边发送文本中标准信息中的msg.url=flow.get("send_kf_url"). 这个变量,已经在第一个流程图中的发布url里,每小时自动声明一次。这个token的时间好像是7200s,频率看着弄就行了。无所谓。





-----------------------------------------------------------
结束了,打字截图很累。







获取聊天记录流程.png
重组节点.png

评分

参与人数 4金钱 +35 收起 理由
Dlian + 5 以为是青铜,原来是王者!
firewater + 10 高手,这是高手!
DDDear + 10 膜拜大神!
隔壁的王叔叔 + 10 纳尼,还有这种操作?

查看全部评分

回复

使用道具 举报

0

主题

19

帖子

420

积分

中级会员

Rank: 3Rank: 3

积分
420
金钱
401
HASS币
0
发表于 2023-8-25 13:13:55 | 显示全部楼层
感谢分享,前排鼓掌
回复

使用道具 举报

5

主题

80

帖子

546

积分

高级会员

Rank: 4

积分
546
金钱
466
HASS币
0
发表于 2023-8-25 13:22:36 | 显示全部楼层
666666666666666
回复

使用道具 举报

3

主题

119

帖子

1560

积分

金牌会员

Rank: 6Rank: 6

积分
1560
金钱
1441
HASS币
0
发表于 2023-8-25 14:02:09 | 显示全部楼层
论坛nodered流复制导入有点问题,能不能发文本压缩包?谢谢
回复

使用道具 举报

35

主题

401

帖子

2559

积分

金牌会员

Rank: 6Rank: 6

积分
2559
金钱
2158
HASS币
10
发表于 2023-8-25 14:03:59 | 显示全部楼层
这样就不需要公网IP了吗?
回复

使用道具 举报

146

主题

2266

帖子

6998

积分

元老级技术达人

积分
6998
金钱
4727
HASS币
30
发表于 2023-8-25 15:10:47 | 显示全部楼层
lexcao 发表于 2023-8-25 14:03
这样就不需要公网IP了吗?

他这个不是微信推送通知,他这个应该是通过微信控制ha
回复

使用道具 举报

12

主题

85

帖子

746

积分

高级会员

Rank: 4

积分
746
金钱
661
HASS币
10
 楼主| 发表于 2023-8-25 16:19:34 | 显示全部楼层
lexcao 发表于 2023-8-25 14:03
这样就不需要公网IP了吗?

不需要,norered通过扒客服聊天记录,来获取微信发出去的消息。  实现微信消息发到node red.
回复

使用道具 举报

12

主题

85

帖子

746

积分

高级会员

Rank: 4

积分
746
金钱
661
HASS币
10
 楼主| 发表于 2023-8-25 16:21:08 | 显示全部楼层
bugensui 发表于 2023-8-25 15:10
他这个不是微信推送通知,他这个应该是通过微信控制ha

文中提了两个接口,但是这个文章主要是说第一个。 第二个接口在最下边只提了一下。就是给微信推送通知。

也就是执行反馈。
回复

使用道具 举报

12

主题

85

帖子

746

积分

高级会员

Rank: 4

积分
746
金钱
661
HASS币
10
 楼主| 发表于 2023-8-25 16:23:09 | 显示全部楼层
jole 发表于 2023-8-25 14:02
论坛nodered流复制导入有点问题,能不能发文本压缩包?谢谢

手动先替换下json里的“替换哦”,随便给个英文字符串就行。  然后再导入。
我是粘贴到帖子之后脱敏的。
回复

使用道具 举报

12

主题

85

帖子

746

积分

高级会员

Rank: 4

积分
746
金钱
661
HASS币
10
 楼主| 发表于 2023-8-25 16:43:26 | 显示全部楼层
  居然忘了说明一个非常重要的内容,就是在哪里发送这个消息。

入口.png
将这个地址发给微信,然后在微信打开。就可以看到客服消息入口。
客服消息.png
再点击自己创建的客服人员,就可以开始发送消息给ha 了。接收到的消息也是在这里。

回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-11-22 11:02 , Processed in 0.154779 second(s), 35 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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