Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/atorber/wechat-remote
一个微信远程调用工具,使用MQTT连接本地或云端微信客户端实现远程操作
https://github.com/atorber/wechat-remote
chatbot mqtt wechaty wechaty-plugin wehcat wehcatbot wxbot
Last synced: 18 days ago
JSON representation
一个微信远程调用工具,使用MQTT连接本地或云端微信客户端实现远程操作
- Host: GitHub
- URL: https://github.com/atorber/wechat-remote
- Owner: atorber
- License: apache-2.0
- Created: 2024-01-17T15:28:53.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2024-02-02T09:24:45.000Z (9 months ago)
- Last Synced: 2024-10-03T09:44:42.426Z (about 1 month ago)
- Topics: chatbot, mqtt, wechaty, wechaty-plugin, wehcat, wehcatbot, wxbot
- Language: TypeScript
- Homepage: https://www.yuque.com/atorber/chatflow/hwqf0tgqg9o51epc
- Size: 116 KB
- Stars: 4
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# WeChatRemote
## 概述
WeChatRemote是一个微信远程调用工具,使用MQTT连接本地或云端微信客户端实现远程操作
- 支持所有的Wechaty Puppet
- 解耦Wechaty客户端与业务应用服务端,使用熟悉语言实现MQTT Client即可调用
- 本地运行bot,远程接收消息和调用bot发消息![原理图](https://cdn.nlark.com/yuque/0/2024/jpeg/250308/1705459538734-81f76086-02e8-4ac2-8fc5-868ce63afc13.jpeg)
## 快速入门
### 安装wechat-remote插件
```shell
npm i wechat-remote
```### 启动机器人
首先启动一个wechaty客户端(目前仅支持nodejs),并使用mqtt-wechaty插件
机器人可以运行在本地或云服务器中,只需要可以访问外网,不需要配置外网IP```typescript
import { WechatyBuilder } from 'wechaty'
import {
QRCodeTerminal,
MqttGateway,
MqttGatewayConfig,
} from 'wechat-remote'const bot = WechatyBuilder.build({
name : 'ding-dong-bot',
})const config: MqttGatewayConfig = {
events: [
'login',
'logout',
'reset',
'ready',
'dirty',
'dong',
'error',
// 'heartbeat',
'friendship',
'message', 'post',
'room-invite', 'room-join',
'room-leave', 'room-topic',
'scan',
],
mqtt: {
clientId: 'ding-dong-test01', // 替换成自己的clientId,建议不少于16个字符串
host: 'broker.emqx.io',
password: '',
port: 1883,
username: '',
},
options:{
secrectKey: '',
simple: false,
},
token: '',
}bot.use(
MqttGateway(config),
QRCodeTerminal(),
)bot.start()
.catch(console.error)```
### MQTTX调用
使用MQTT可视化工具调用接口,可以快速理解学习WeChatRemote使用
1. 访问 [http://www.emqx.io/online-mqtt-client](http://www.emqx.io/online-mqtt-client) ,配置并连接MQTT
2. 订阅如下主题,其中的“chatbot/”之后的“+”可以换成具体的clientId
- 接收事件 thing/chatbot/+/event/post
- 应用端下发指令 thing/chatbot/+/command/invoke
- 接收响应 thing/chatbot/+/response/d2c/+
3. 查询机器人状态,向 thing/chatbot/ding-dong-test01/command/invoke 主题发布如下payload:```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"wechatyLogonoff",
"params":{}
}
```![image.png](https://cdn.nlark.com/yuque/0/2024/png/250308/1705456827915-8e1ace3a-3fa2-414f-9104-e861468e3f48.png#averageHue=%23dff5e0&clientId=uadef19d5-ced0-4&from=paste&height=1040&id=u2b7b76d0&originHeight=1040&originWidth=1918&originalType=binary&ratio=1&rotation=0&showTitle=false&size=308523&status=done&style=none&taskId=uad897fa2-96d1-470e-bb8e-dc2655cd408&title=&width=1918)
4. 向指定好友发送消息,向 thing/chatbot/ding-dong-test01/command/invoke 主题发布如下payload:```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"contactSay",
"params":{
"contacts":["atorber"],
"messageType":"Text",
"messagePayload":"hello"
}
}
```![image.png](https://cdn.nlark.com/yuque/0/2024/png/250308/1705457339087-f8a1d427-2596-45a7-b6ea-4b11f3880ebd.png#averageHue=%23fefefd&clientId=uadef19d5-ced0-4&from=paste&height=1039&id=ubd817504&originHeight=1039&originWidth=1917&originalType=binary&ratio=1&rotation=0&showTitle=false&size=304967&status=done&style=none&taskId=uea142729-c52c-42bb-a3d0-9fe0c0c9944&title=&width=1917)
> 下载安装MQTTX [https://mqttx.app/zh/downloads](https://mqttx.app/zh/downloads) 可以使用客户端更加稳定
### 程序调用
以下是几种常用语言的SimpleCode,后续考虑提供SDK,期待大家贡献各种语言的sdk
#### JavaScript
- 安装依赖
```shell
npm install mqtt
```- 接收消息
```javascript
const mqtt = require('mqtt');// MQTT 服务器设置
const MQTT_BROKER_URL = 'mqtt://your-mqtt-broker-url';
const TOPIC = 'thing/chatbot/xxxx/event/post';
const MQTT_PORT = 1883; // 替换为你的 MQTT 服务器端口
const USERNAME = 'your-username'; // 替换为你的用户名
const PASSWORD = 'your-password'; // 替换为你的密码// 连接选项
const options = {
port: MQTT_PORT,
username: USERNAME,
password: PASSWORD,
};// 创建 MQTT 客户端
const client = mqtt.connect(MQTT_BROKER_URL, options);client.on('connect', () => {
console.log('Connected to MQTT Broker:', MQTT_BROKER_URL);
// 订阅指定主题
client.subscribe(TOPIC, (err) => {
if (!err) {
console.log(`Subscribed to topic: ${TOPIC}`);
} else {
console.error(`Failed to subscribe: ${err}`);
}
});
});client.on('message', (topic, message) => {
if (topic === TOPIC) {
try {
// 尝试解析消息为 JSON
const jsonMessage = JSON.parse(message.toString());
console.log('Received JSON Message:', jsonMessage);
} catch (error) {
console.error('Received non-JSON message:', message.toString());
}
}
});client.on('error', (error) => {
console.error('MQTT Client Error:', error);
});
```- 调用API
```javascript
const mqtt = require('mqtt');const MQTT_BROKER_URL = 'mqtt://your-mqtt-broker-url';
const COMMAND_TOPIC = 'thing/chatbot/xxxx/command/invoke';
const RESPONSE_TOPIC = 'thing/chatbot/xxxx/response/d2c/+';
const MQTT_PORT = 1883; // 或者你的 MQTT 服务器端口
const USERNAME = 'your-username'; // 或者你的用户名
const PASSWORD = 'your-password'; // 或者你的密码const message = {
reqId: "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
method: "command",
version: "1.0",
timestamp: 1705384610041,
name: "contactSay",
params: {
contacts: ["ledongmao", "choogoo"],
messageType: "Text",
messagePayload: "hello"
}
};const options = {
port: MQTT_PORT,
username: USERNAME,
password: PASSWORD,
};const client = mqtt.connect(MQTT_BROKER_URL, options);
client.on('connect', () => {
console.log('Connected to MQTT Broker:', MQTT_BROKER_URL);// 订阅响应主题
client.subscribe(RESPONSE_TOPIC, (err) => {
if (!err) {
console.log(`Subscribed to response topic: ${RESPONSE_TOPIC}`);
} else {
console.error(`Failed to subscribe: ${err}`);
}
});// 发布命令消息
client.publish(COMMAND_TOPIC, JSON.stringify(message));
console.log(`Message published to command topic: ${COMMAND_TOPIC}`);
});client.on('message', (topic, message) => {
console.log(`Received message from ${topic}: ${message.toString()}`);
});client.on('error', (error) => {
console.error('MQTT Client Error:', error);
});
```#### TypeScript
- 安装依赖
```shell
npm install mqtt
npm install @types/node --save-dev
```- 接收消息
```typescript
import * as mqtt from 'mqtt';// MQTT 服务器设置
const MQTT_BROKER_URL = 'mqtt://your-mqtt-broker-url';
const TOPIC = 'thing/chatbot/xxxx/event/post';
const MQTT_PORT = 1883; // 替换为你的 MQTT 服务器端口
const USERNAME = 'your-username'; // 替换为你的用户名
const PASSWORD = 'your-password'; // 替换为你的密码// 连接选项
const options: mqtt.IClientOptions = {
port: MQTT_PORT,
username: USERNAME,
password: PASSWORD,
};// 创建 MQTT 客户端
const client = mqtt.connect(MQTT_BROKER_URL, options);client.on('connect', () => {
console.log('Connected to MQTT Broker:', MQTT_BROKER_URL);
// 订阅指定主题
client.subscribe(TOPIC, (err) => {
if (!err) {
console.log(`Subscribed to topic: ${TOPIC}`);
} else {
console.error(`Failed to subscribe: ${err}`);
}
});
// 订阅指定主题
client.subscribe(TOPIC, (err) => {
if (!err) {
console.log(`Subscribed to topic: ${TOPIC}`);
} else {
console.error(`Failed to subscribe: ${err}`);
}
});
});client.on('message', (topic, message) => {
if (topic === TOPIC) {
try {
// 尝试解析消息为 JSON
const jsonMessage = JSON.parse(message.toString());
console.log('Received JSON Message:', jsonMessage);
} catch (error) {
console.error('Received non-JSON message:', message.toString());
}
}
});client.on('error', (error) => {
console.error('MQTT Client Error:', error);
});
```- 调用API
```typescript
import * as mqtt from 'mqtt';
import type { IClientOptions, MqttClient } from 'mqtt';const MQTT_BROKER_URL: string = 'mqtt://your-mqtt-broker-url';
const COMMAND_TOPIC: string = 'thing/chatbot/xxxx/command/invoke';
const RESPONSE_TOPIC: string = 'thing/chatbot/xxxx/response/d2c/+';
const MQTT_PORT: number = 1883; // 或者你的 MQTT 服务器端口
const USERNAME: string = 'your-username'; // 或者你的用户名
const PASSWORD: string = 'your-password'; // 或者你的密码interface Message {
reqId: string;
method: string;
version: string;
timestamp: number;
name: string;
params: {
contacts: string[];
messageType: string;
messagePayload: string;
};
}const message: Message = {
reqId: "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
method: "command",
version: "1.0",
timestamp: 1705384610041,
name: "contactSay",
params: {
contacts: ["ledongmao", "choogoo"],
messageType: "Text",
messagePayload: "hello"
}
};const options: IClientOptions = {
port: MQTT_PORT,
username: USERNAME,
password: PASSWORD,
};const client: MqttClient = mqtt.connect(MQTT_BROKER_URL, options);
client.on('connect', () => {
console.log('Connected to MQTT Broker:', MQTT_BROKER_URL);// 订阅响应主题
client.subscribe(RESPONSE_TOPIC, (err) => {
if (!err) {
console.log(`Subscribed to response topic: ${RESPONSE_TOPIC}`);
} else {
console.error(`Failed to subscribe: ${err}`);
}
});// 发布命令消息
client.publish(COMMAND_TOPIC, JSON.stringify(message));
console.log(`Message published to command topic: ${COMMAND_TOPIC}`);
});client.on('message', (topic: string, message: Buffer) => {
console.log(`Received message from ${topic}: ${message.toString()}`);
});client.on('error', (error: Error) => {
console.error('MQTT Client Error:', error);
});
```#### Python
- 安装依赖
```shell
pip install paho-mqtt
```- 接收消息
```python
import json
import paho.mqtt.client as mqtt# MQTT 服务器设置
MQTT_BROKER_URL = 'mqtt://your-mqtt-broker-url'
TOPIC = 'thing/chatbot/xxxx/event/post'
MQTT_PORT = 1883 # 替换为你的 MQTT 服务器端口
USERNAME = 'your-username' # 替换为你的用户名
PASSWORD = 'your-password' # 替换为你的密码# 连接成功回调函数
def on_connect(client, userdata, flags, rc):
print(f'Connected to MQTT Broker: {MQTT_BROKER_URL}')
client.subscribe(TOPIC)
print(f'Subscribed to topic: {TOPIC}')# 接收消息回调函数
def on_message(client, userdata, msg):
if msg.topic == TOPIC:
try:
# 尝试解析消息为 JSON
json_message = json.loads(msg.payload.decode())
print('Received JSON Message:', json_message)
except ValueError:
print('Received non-JSON message:', msg.payload.decode())# MQTT 客户端设置
client = mqtt.Client()
client.username_pw_set(USERNAME, PASSWORD)
client.on_connect = on_connect
client.on_message = on_message# 连接 MQTT Broker
client.connect(MQTT_BROKER_URL, MQTT_PORT, 60)# 网络循环,以处理回调函数并保持脚本运行
client.loop_forever()
```- 调用API
```python
import json
import paho.mqtt.client as mqttMQTT_BROKER_URL = 'mqtt://your-mqtt-broker-url'
COMMAND_TOPIC = 'thing/chatbot/xxxx/command/invoke'
RESPONSE_TOPIC = 'thing/chatbot/xxxx/response/d2c/+'
MQTT_PORT = 1883 # 或者你的 MQTT 服务器端口
USERNAME = 'your-username' # 或者你的用户名
PASSWORD = 'your-password' # 或者你的密码message = {
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "command",
"version": "1.0",
"timestamp": 1705384610041,
"name": "contactSay",
"params": {
"contacts": ["ledongmao", "choogoo"],
"messageType": "Text",
"messagePayload": "hello"
}
}def on_connect(client, userdata, flags, rc):
print(f"Connected to MQTT Broker: {MQTT_BROKER_URL}")# 订阅响应主题
client.subscribe(RESPONSE_TOPIC)
print(f"Subscribed to response topic: {RESPONSE_TOPIC}")# 发布命令消息
client.publish(COMMAND_TOPIC, json.dumps(message))
print(f"Message published to command topic: {COMMAND_TOPIC}")def on_message(client, userdata, msg):
print(f"Received message from {msg.topic}: {msg.payload.decode()}")def on_error(client, userdata, rc):
print(f"MQTT Client Error: {rc}")client = mqtt.Client()
client.username_pw_set(USERNAME, PASSWORD)
client.on_connect = on_connect
client.on_message = on_message
client.on_error = on_errorclient.connect(MQTT_BROKER_URL.replace('mqtt://', ''), MQTT_PORT, 60)
client.loop_forever()
```#### Go
- 安装依赖
```shell
go get github.com/eclipse/paho.mqtt.golang
```- 接收消息
```go
package mainimport (
"encoding/json"
"fmt"
"os"
"time"mqtt "github.com/eclipse/paho.mqtt.golang"
)const (
MQTT_BROKER_URL = "tcp://your-mqtt-broker-url:1883" // 注意更换为你的 MQTT 服务器地址和端口
TOPIC = "thing/chatbot/xxxx/event/post" // 更换为你的主题
USERNAME = "your-username" // 更换为你的用户名
PASSWORD = "your-password" // 更换为你的密码
)func onConnectHandler(client mqtt.Client) {
if token := client.Subscribe(TOPIC, 0, onMessageReceivedHandler); token.Wait() && token.Error() != nil {
fmt.Println("Subscribe error:", token.Error())
os.Exit(1)
}
fmt.Println("Connected to MQTT Broker:", MQTT_BROKER_URL)
fmt.Println("Subscribed to topic:", TOPIC)
}func onMessageReceivedHandler(client mqtt.Client, msg mqtt.Message) {
fmt.Printf("Received message on topic %s: %s\n", msg.Topic(), string(msg.Payload()))var jsonMessage map[string]interface{}
if err := json.Unmarshal(msg.Payload(), &jsonMessage); err != nil {
fmt.Println("Error parsing JSON message:", err)
} else {
fmt.Println("Received JSON Message:", jsonMessage)
}
}func main() {
opts := mqtt.NewClientOptions().AddBroker(MQTT_BROKER_URL).SetUsername(USERNAME).SetPassword(PASSWORD)
opts.SetDefaultPublishHandler(onMessageReceivedHandler)
opts.OnConnect = onConnectHandlerclient := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
fmt.Println("Connection error:", token.Error())
os.Exit(1)
}// Keep the main function running until interrupted
select {}
}
```- API调用
#### Java
- 安装依赖
```shell
org.eclipse.paho
org.eclipse.paho.client.mqttv3
1.2.5
```
- 接收消息
```shell
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONObject;public class MqttSubscribeSample {
public static void main(String[] args) {
final String brokerUrl = "tcp://your-mqtt-broker-url:1883"; // 替换为你的MQTT Broker的URL
final String topic = "thing/chatbot/xxxx/event/post"; // 替换为你的主题
final String clientId = "JavaClient";
final String username = "your-username"; // 替换为你的用户名
final String password = "your-password"; // 替换为你的密码
try {
MqttClient sampleClient = new MqttClient(brokerUrl, clientId);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
connOpts.setUserName(username);
connOpts.setPassword(password.toCharArray());
System.out.println("Connecting to broker: " + brokerUrl);
sampleClient.connect(connOpts);
System.out.println("Connected");
sampleClient.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
System.out.println("Connection lost!");
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println("Message arrived: " + message.toString());
try {
JSONObject jsonMessage = new JSONObject(message.toString());
System.out.println("Received JSON Message: " + jsonMessage.toString(2)); // Indent with 2 spaces
} catch (Exception e) {
System.out.println("Received non-JSON message: " + message.toString());
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// Not used in this example
}
});
System.out.println("Subscribing to topic: " + topic);
sampleClient.subscribe(topic);
} catch(Exception e) {
System.out.println("Exception: " + e.getMessage());
}
}
```- API调用
```go
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONObject;public class MqttClientDemo {
private static final String MQTT_BROKER_URL = "tcp://your-mqtt-broker-url:1883";
private static final String COMMAND_TOPIC = "thing/chatbot/xxxx/command/invoke";
private static final String RESPONSE_TOPIC = "thing/chatbot/xxxx/response/d2c/+";
private static final String USERNAME = "your-username";
private static final String PASSWORD = "your-password";public static void main(String[] args) {
try {
MqttClient client = new MqttClient(MQTT_BROKER_URL, MqttClient.generateClientId());
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(USERNAME);
options.setPassword(PASSWORD.toCharArray());
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
System.out.println("MQTT Client Error: " + cause.getMessage());
}@Override
public void messageArrived(String topic, MqttMessage message) {
System.out.println("Received message from " + topic + ": " + new String(message.getPayload()));
}@Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
});client.connect(options);
System.out.println("Connected to MQTT Broker: " + MQTT_BROKER_URL);
client.subscribe(RESPONSE_TOPIC);
System.out.println("Subscribed to response topic: " + RESPONSE_TOPIC);
JSONObject message = new JSONObject();
message.put("reqId", "2a42cff1-bfb5-4d5d-b185-353c8c71a00b");
message.put("method", "command");
message.put("version", "1.0");
message.put("timestamp", 1705384610041L);
message.put("name", "contactSay");
JSONObject params = new JSONObject();
params.put("contacts", new String[]{"ledongmao", "choogoo"});
params.put("messageType", "Text");
params.put("messagePayload", "hello");
message.put("params", params);client.publish(COMMAND_TOPIC, new MqttMessage(message.toString().getBytes()));
System.out.println("Message published to command topic: " + COMMAND_TOPIC);} catch (MqttException e) {
e.printStackTrace();
}
}
}
```> 其他语言示例欢迎在评论里粘贴代码或提需求,也可以交给GPTs [多语言代码转换大师](https://chat.openai.com/g/g-TgFzzIJjo-duo-yu-yan-dai-ma-zhuan-huan-da-shi)
## API说明
:::warning
目前仅实现了常用API的支持,其他API需求可以在评论中留言,当然API的范围不能超出Wechaty支持范围
:::
远程调用调用端向 thing/chatbot/${clinetId}/command/invoke发送调用指令(其中${clinetId}表示具体的clientId)
Wechaty客户端接收到指令后向thing/chatbot/${clinetId}/response/d2c/${reqId}主题推送响应消息
应用端订阅响应消息:- 订阅指定请求消息:thing/chatbot/xxxx/response/d2c/1234
- 订阅所有请求消息:thing/chatbot/xxxx/response/d2c/+### 查询机器人状态
- 请求
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"wechatyLogonoff",
"params":{}
}
```- 响应
```json
{
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "response",
"version": "1.0",
"timestamp": 1705408082094,
"name": "wechatyLogonoff",
"code": 200,
"message": "success",
"params": {
"logonoff": true
}
}
```### 获取机器人信息
- 请求
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"wechatyUserSelf",
"params":{}
}
```- 响应
```json
{
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "response",
"version": "1.0",
"timestamp": 1705408574486,
"name": "wechatyUserSelf",
"code": 200,
"message": "success",
"params": {
"_events": {},
"_eventsCount": 0,
"id": "@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"payload": {
"alias": "",
"avatar": "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=1851844649&username=@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299&skey=@crypt_3f47a99d_1d59eeac1c79b47948fa86522b106b12",
"friend": false,
"gender": 2,
"id": "@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"name": "瓦力",
"phone": [],
"star": false,
"type": 1
}
}
}
```### 获取好友列表
- 请求
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"contactFindAll",
"params":{
"size":100
}
}
```- 响应
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"response",
"version":"1.0",
"timestamp":1705384610041,
"code":200,
"message":"success",
"name":"contactFindAll",
"params":{
"page":1,
"size":100,
"total":3500,
"items":[
{
"_events":{},
"_eventsCount":0,
"id":"@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"payload":{
"alias":"",
"avatar":"/cgi-bin/mmwebwx-bin/webwxgeticon?seq=11550719&username=@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299&skey=@crypt_3f47a99d_1d59eeac1c79b47948fa86522b106b12",
"friend":false,
"gender":2,
"id":"@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"name":"瓦力",
"phone":[],
"star":false,
"type":1
}
},
{
"_events":{},
"_eventsCount":0,
"id":"@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"payload":{
"alias":"",
"avatar":"/cgi-bin/mmwebwx-bin/webwxgeticon?seq=11550719&username=@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299&skey=@crypt_3f47a99d_1d59eeac1c79b47948fa86522b106b12",
"friend":false,
"gender":2,
"id":"@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"name":"瓦力",
"phone":[],
"star":false,
"type":1
}
}
]
}
}
```### 查询好友详情
- 请求
alias、id、name至少填写一个
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"contactFind",
"params":{
"alias":"",
"id":"@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"name":"瓦力"
}
}
```- 响应
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"response",
"version":"1.0",
"timestamp":1705384610041,
"code":200,
"message":"success",
"name":"contactFind",
"params":{
"_events":{},
"_eventsCount":0,
"id":"@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"payload":{
"alias":"",
"avatar":"/cgi-bin/mmwebwx-bin/webwxgeticon?seq=11550719&username=@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299&skey=@crypt_3f47a99d_1d59eeac1c79b47948fa86522b106b12",
"friend":false,
"gender":2,
"id":"@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"name":"瓦力",
"phone":[],
"star":false,
"type":1
}
}
}
```### 向指定好友发消息
> 目前仅支持发送文本消息,图片、文件、视频、语音等消息即将支持
- 请求
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"contactSay",
"params":{
"contacts":[
"ledongmao",
"choogoo"
],
"messageType":"Text",
"messagePayload":"hello"
}
}
```- 响应
返回发送结果列表
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"response",
"version":"1.0",
"timestamp":1705384610041,
"code":200,
"message":"success",
"name":"contactSay",
"params":{
"success":[],
"fail":[]
}
}
```### 获取群列表
- 请求
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"roomFindAll",
"params":{
"size":100
}
}
```- 响应
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"response",
"version":"1.0",
"timestamp":1705384610041,
"code":200,
"message":"success",
"name":"roomFindAll",
"params":{
"page":1,
"size":100,
"count":3500,
"items":[
{
"_events":{},
"_eventsCount":0,
"id":"19036636423@chatroom",
"payload":{
"adminIdList":[],
"avatar":"",
"external":false,
"id":"19036636423@chatroom",
"ownerId":"",
"topic":"宁波金茂汇项目团队"
}
},
{
"_events":{},
"_eventsCount":0,
"id":"19036636423@chatroom",
"payload":{
"adminIdList":[],
"avatar":"",
"external":false,
"id":"19036636423@chatroom",
"ownerId":"",
"topic":"宁波金茂汇项目团队"
}
}
]
}
}
```### 获取群详情
- 请求
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"roomFind",
"params":{
"id":"@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"topic":"瓦力是群主"
}
}
```- 响应
```json
{
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "response",
"version": "1.0",
"timestamp": 1705418869966,
"name": "roomFind",
"code": 200,
"message": "success",
"params": {
"_events": {},
"_eventsCount": 0,
"id": "5550027590@chatroom",
"payload": {
"adminIdList": [
"wxid_m7kf9tq12"
],
"avatar": "",
"external": false,
"id": "5550027590@chatroom",
"memberIdList": [
"wxid_m7kf9tq12",
"tyutl",
"wxid_0f57221"
],
"ownerId": "wxid_m7kf9tq12",
"topic": "瓦力是群主"
}
}
}
```### 查询群成员列表
- 请求
id、topic至少填写一项
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"roomMemberAllGet",
"params":{
"size":100,
"id":"@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"topic":"瓦力是群主"
}
}
```- 响应
```json
{
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "response",
"version": "1.0",
"timestamp": 1705462410448,
"name": "roomMemberAllGet",
"code": 200,
"message": "success",
"params": {
"page": 1,
"size": 100,
"total": 3,
"items": [
{
"_events": {},
"_eventsCount": 0,
"id": "wxid_pnza7m7kf9tq12",
"payload": {
"alias": "",
"friend": true,
"id": "wxid_pnza7m7kf9tq12",
"name": "瓦力",
"phone": [],
"type": 1
}
},
{
"_events": {},
"_eventsCount": 0,
"id": "tyutluyc",
"payload": {
"alias": "超哥",
"friend": true,
"id": "tyutluyc",
"name": "luyuchao",
"phone": [],
"type": 1
}
},
{
"_events": {},
"_eventsCount": 0,
"id": "wxid_0o1t51l3f57221",
"payload": {
"alias": "",
"avatar": "https://wx.qlogo.cn/mmhead/ver_1/xUlBgtTamVSCTw5KnGTxusBCT6eSQSgwDoRnp18ICZRp5JcWWFju1aLCzj5UurApCMDcLmfGOyxvDSwPL9yyoIB9zug49f5QjbI2HTk4ib1w/132",
"friend": false,
"gender": 0,
"id": "wxid_0o1t51l3f57221",
"name": "大师",
"phone": [],
"type": 1
}
}
]
}
}
```### 向指定群发消息
> 目前仅支持发送文本消息,图片、文件、视频、语音等消息即将支持
- 请求
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"roomSay",
"params":{
"rooms":[
"[email protected]"
],
"messageType":"Text",
"messagePayload":"hello"
}
}
```- 响应
```json
{
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "response",
"version": "1.0",
"timestamp": 1705461448305,
"name": "roomSay",
"code": 200,
"message": "success",
"params": {
"id": "[email protected]"
}
}
```### @指定群好友
有瑕疵,调试中...
- 请求
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"roomSayAt",
"params":{
"contacts":[
"ledongmao",
"choogoo"
],
"room":"[email protected]",
"messageType":"Text",
"messagePayload":"hello"
}
}
```- 响应
```json
{
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "response",
"version": "1.0",
"timestamp": 1705462056289,
"name": "roomSayAt",
"code": 200,
"message": "success"
}
```### 回复消息
- 请求
```json
{
"reqId":"2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method":"command",
"version":"1.0",
"timestamp":1705384610041,
"name":"messageSay",
"params":{
"id":"xxxxx",
"messageType":"Text",
"messagePayload":"hello"
}
}
```- 响应
```json
{
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "response",
"version": "1.0",
"timestamp": 1705463098535,
"name": "messageSay",
"code": 200,
"message": "success",
"params": {
"id": "clrh8op130002yszc9col2coq"
}
}
``````json
{
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "response",
"version": "1.0",
"timestamp": 1705463049890,
"name": "messageSay",
"code": 200,
"message": "消息不存在",
"params": {}
}
```## 事件消息推送
事件被推送到 thing/chatbot/${clinetId}/event/post主题(其中${clinetId}表示具体的clientId)
订阅thing/chatbot/xxxx/event/post接收事件数据### 扫码 scan
```json
{
"reqId": "2a42cff1-bfb5-4d5d-b185-353c8c71a00b",
"method": "event",
"version": "1.0",
"timestamp": 1705384610041,
"name": "scan",
"params": {
"qrcode": "https://login.weixin.qq.com/l/gaD8UC3bcA==",
"status": 2
}
}
```### 登录 login
```json
{
"reqId": "6e80b9ce-3585-46d2-982c-9be0087f21e2",
"method": "event",
"version": "1.0",
"timestamp": 1705384714220,
"name": "login",
"params": {
"_events": {},
"_eventsCount": 0,
"id": "@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"payload": {
"alias": "",
"avatar": "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=11550719&username=@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299&skey=@crypt_3f47a99d_1d59eeac1c79b47948fa86522b106b12",
"friend": false,
"gender": 2,
"id": "@a4c7b5b71eb79b5f790f5d4c2270b0f3b787952a3a8ca08b228efe4832021299",
"name": "瓦力",
"phone": [],
"star": false,
"type": 1
}
}
}
```### 登出 logout
```json
{
"reqId": "e0e8fb62-42a0-4b7c-9217-c3aadb9059dd",
"method": "event",
"version": "1.0",
"timestamp": 1705384609786,
"name": "logout",
"params": [
{
"_events": {},
"_eventsCount": 0,
"id": "@85ee0016d30773031e259b3de554c8542340104d9b7a2c2646f73076b990130a",
"payload": {
"alias": "",
"avatar": "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=1946854219&username=@85ee0016d30773031e259b3de554c8542340104d9b7a2c2646f73076b990130a&skey=@crypt_3f47a99d_291be9b57007f9ec09ccd9cfda807c9c",
"friend": false,
"gender": 2,
"id": "@85ee0016d30773031e259b3de554c8542340104d9b7a2c2646f73076b990130a",
"name": "瓦力",
"phone": [],
"star": false,
"type": 1
}
},
"logout()"
]
}
```### 准备就绪 ready
```json
{
"reqId": "46d3bcb9-f21b-4236-91a3-88efb99ff9f9",
"method": "event",
"version": "1.0",
"timestamp": 1705384530329,
"name": "ready",
"params": []
}
```### 错误 error
```json
{
"reqId": "52bd5dae-6cf5-44bb-a76c-982744ba585e",
"method": "event",
"version": "1.0",
"timestamp": 1705384604626,
"name": "error",
"params": [
{
"code": 2,
"details": "Error: 连续3次同步失败,5s后尝试重启\n at C:\\Users\\Administrator\\Documents\\GitHub\\plugin-contrib\\node_modules\\wechat4u\\src\\wechat.js:100:19\n at processTicksAndRejections (node:internal/process/task_queues:96:5)",
"message": "连续3次同步失败,5s后尝试重启",
"name": "Error",
"stack": "Error: 连续3次同步失败,5s后尝试重启\n at C:\\Users\\Administrator\\Documents\\GitHub\\plugin-contrib\\node_modules\\wechat4u\\src\\wechat.js:100:19\n at processTicksAndRejections (node:internal/process/task_queues:96:5)"
}
]
}
```### 消息 message
```json
{
"reqId": "2ee3362b-3142-44d5-b859-a15cb4177445",
"method": "event",
"version": "1.0",
"timestamp": 1705384017113,
"name": "message",
"params": {
"_events": {},
"_eventsCount": 0,
"id": "8768818756347691243",
"payload": {
"id": "8768818756347691243",
"talkerId": "@d3cc07d80f9add1b4acd87e49817d061",
"text": "h",
"timestamp": 1705384016,
"type": 7,
"roomId": "@@e3e01b946e9f19978ad0718269b78b4f5dc853fd8eda5aa2dd5601ac57cdb3a5",
"mentionIdList": []
}
}
}
``````json
{
"reqId": "b8ae2de2-19a3-4533-a5d5-9c2b7630a113",
"method": "thing.event.post",
"version": "1.0",
"timestamp": 1705385708810,
"events": {
"onMessage": {
"_id": "clrfyma84006vropd2i4ecmax",
"data": {
"_events": {},
"_eventsCount": 0,
"id": "clrfyma84006vropd2i4ecmax",
"payload": {
"id": "clrfyma84006vropd2i4ecmax",
"listenerId": "",
"roomId": "19036636423@chatroom",
"talkerId": "wxid_zqbyd7b5kwy322",
"text": "各位领导、同事\n 关于集团第四季度模拟钓鱼邮件演练,金茂商业有7名同事点击钓鱼链接,按总部要求加强各单位钓鱼邮件的识别、防御和处理能力。\n我们项目出现中招情况,故此,进行项目全员钓鱼邮件专题考试,希望大家在钓鱼邮件方面进一步加强安全意识意识和处置技能。\n以下为考试链接,请全员在1月19日前完成考试,我们将在群内公示考试人数。\nhttps://docs.chinajinmao.cn/form/ew/HOasNVyb/\n邀你填写「预防钓鱼邮件专题考试」",
"timestamp": 1705385708356,
"toId": "",
"type": 7
}
},
"room": {
"_events": {},
"_eventsCount": 0,
"id": "19036636423@chatroom",
"payload": {
"adminIdList": [],
"avatar": "",
"external": false,
"id": "19036636423@chatroom",
"ownerId": "",
"topic": "宁波金茂汇项目团队"
}
},
"talker": {
"_events": {},
"_eventsCount": 0,
"id": "wxid_zqbyd7b5kwy322",
"payload": {
"friend": true,
"id": "wxid_zqbyd7b5kwy322",
"name": "清昼",
"phone": [],
"type": 1
}
},
"time": "56011-07-10 20:19:16",
"timestamp": 1705385708356000
}
}
}
```### 心跳 heartbeat
### 好友关系 friendship
### 邀请进群 room-invite
### 加入群 room-join
### 离开群 room-leave
### 群名称变更 room-topic
### 重载 dirty
## 附录
### Wechaty文档
[https://wechaty.js.org/docs/api/wechaty](https://wechaty.js.org/docs/api/wechaty)
### Wechaty事件定义
| Name | Type | Description |
| --- | --- | --- |
| error | string | When the bot get error, there will be a Wechaty error event fired. |
| login | string | After the bot login full successful, the event login will be emitted, with a Contact of current logined user. |
| logout | string | Logout will be emitted when bot detected log out, with a Contact of the current login user. |
| heartbeat | string | Get bot's heartbeat. |
| friendship | string | When someone sends you a friend request, there will be a Wechaty friendship event fired. |
| message | string | Emit when there's a new message. |
| ready | string | Emit when all data has load completed, in wechaty-puppet-padchat, it means it has sync Contact and Room completed |
| room-join | string | Emit when anyone join any room. |
| room-topic | string | Get topic event, emitted when someone change room topic. |
| room-leave | string | Emit when anyone leave the room. |
| room-invite | string | Emit when there is a room invitation, see more in [RoomInvitation](https://wechaty.js.org/docs/api/room-invitation)
If someone leaves the room by themselves, wechat will not notice other people in the room, so the bot will never get the "leave" event. |
| scan | string | A scan event will be emitted when the bot needs to show you a QR Code for scanning. It is recommend to install qrcode-terminal(run npm install qrcode-terminal) in order to show qrcode in the terminal. |### 案例
[https://www.yuque.com/atorber/chatflow/ei64dvh6ba21yfes](https://www.yuque.com/atorber/chatflow/ei64dvh6ba21yfes)
[https://github.com/atorber/chatbot-iot-terminal](https://github.com/atorber/chatbot-iot-terminal)