FoxESS M1 Microinverter – Local WiFi Protocol Reverse Engineered (ESP-MESH / JSON)
Posted: Thu Apr 02, 2026 8:10 am
Hi all,
I've spent some time doing network analysis on the FoxESS M1 microinverter trying to achieve local data access without cloud dependency. I'm posting my full findings here since I haven't seen this documented anywhere for the M1 specifically. Hopefully useful for others going down the same path.
---
## Setup
- Inverter: FoxESS M1 microinverter
- Network: M1 on isolated IoT VLAN
- Goal: local real-time data access, no FoxESS cloud
---
## Step 1 — Modbus TCP (Not Working!)
The obvious first attempt. Full TCP port scan of all 65535 ports returns zero open ports. The M1 does not run a Modbus TCP server, an HTTP server, or any other inbound TCP service. This is fundamentally different from the H/KH hybrid inverters.
UDP scan found three ports in open|filtered state: 6364, 6366, 61721.
---
## Step 2 — Traffic capture (tcpdump)
Capturing all traffic from the M1 revealed two types of broadcast packets it sends spontaneously.
**Port 6364 UDP — ESP-MESH join request, broadcast every ~2 seconds:**
```json
{
"monkey": 12345678,
"type": "join_me_req",
"seq": 181092959,
"payload": {
"router": -74,
"vendor_id": 45324,
"mesh_id": 24,
"fix_root": 0,
"node_number": 0,
"max_node_number": 0,
"temp_mesh_id": 185,
"mac": "xx:xx:xx:xx:xx:xx"
}
}
```
**Port 3334 UDP — binary heartbeat, broadcast every ~12 seconds:**
```
7f7f ff69 ce7b 7100 0101 xxxx f7f7
```
The 6th byte increments by 0x0c each packet — an uptime counter. Fixed header `7f7f`, fixed device ID bytes, checksum at end.
---
## Step 3 — What the M1 is doing
The M1 runs on an **ESP32 chip** and implements **Espressif ESP-MESH protocol**. It continuously broadcasts `join_me_req` looking for a mesh root/gateway node. Key identifiers:
- `vendor_id: 45324` — FoxESS-specific identifier
- `mesh_id: 24` — mesh network ID
In a normal M1 installation this mesh root would be the **FoxESS M1 gateway/hub device**. Without it, the M1 loops forever broadcasting join requests and never sends solar data locally.
**There is no local API.** The M1 does not expose any queryable interface over WiFi.
---
## Step 4 — Cloud connection analysis
Despite having no gateway, the M1 does eventually establish an outbound TCP connection to a FoxESS cloud server on a non-standard high port. This connection carries encrypted data — likely TLS. The M1 also repeatedly attempts TCP connections to a secondary IP (192.168.1.1) on port 6666 which never succeeds in my setup.
The M1 also ARPs directly for the cloud server's IP address rather than routing via its default gateway — this appears to be a firmware bug or quirk where it treats the cloud server IP as if it were on the local subnet. This means it can only reach the cloud if it happens to get an ARP reply, which normally comes from the FoxESS hub acting as a mesh root and providing connectivity.
---
## Conclusions
1. **The M1 has no local API** — no Modbus TCP, no HTTP, nothing inbound
2. **ESP-MESH is the local protocol** — the M1 is designed to join a mesh network rooted at a FoxESS hub device
3. **Solar data only flows after mesh join** — until `join_me_req` gets a `join_me_resp`, no data packets are sent
4. **The hub is the key** — whoever has an M1 gateway/hub device and can capture what it sends back as `join_me_resp` holds the answer to local integration
5. **Cloud traffic is encrypted** — intercepting the cloud connection is not a practical path
---
## Questions for the community
1. Does anyone own the **FoxESS M1 hub/gateway device**? Can you capture what it sends back to the M1 on port 6364 as a `join_me_resp`?
2. Has anyone found `vendor_id: 45324` or `mesh_id: 24` in any ESP-MESH open source project?
3. Does the M1 hub expose a local HTTP or Modbus interface once the mesh is established?
If someone can capture the hub's response, it should be possible to build a software mesh root — either a Python script or an ESP32 board — that impersonates the hub and receives the M1's solar data locally without any FoxESS cloud involvement.
Happy to share full tcpdump output if useful.
Thanks
I've spent some time doing network analysis on the FoxESS M1 microinverter trying to achieve local data access without cloud dependency. I'm posting my full findings here since I haven't seen this documented anywhere for the M1 specifically. Hopefully useful for others going down the same path.
---
## Setup
- Inverter: FoxESS M1 microinverter
- Network: M1 on isolated IoT VLAN
- Goal: local real-time data access, no FoxESS cloud
---
## Step 1 — Modbus TCP (Not Working!)
The obvious first attempt. Full TCP port scan of all 65535 ports returns zero open ports. The M1 does not run a Modbus TCP server, an HTTP server, or any other inbound TCP service. This is fundamentally different from the H/KH hybrid inverters.
UDP scan found three ports in open|filtered state: 6364, 6366, 61721.
---
## Step 2 — Traffic capture (tcpdump)
Capturing all traffic from the M1 revealed two types of broadcast packets it sends spontaneously.
**Port 6364 UDP — ESP-MESH join request, broadcast every ~2 seconds:**
```json
{
"monkey": 12345678,
"type": "join_me_req",
"seq": 181092959,
"payload": {
"router": -74,
"vendor_id": 45324,
"mesh_id": 24,
"fix_root": 0,
"node_number": 0,
"max_node_number": 0,
"temp_mesh_id": 185,
"mac": "xx:xx:xx:xx:xx:xx"
}
}
```
**Port 3334 UDP — binary heartbeat, broadcast every ~12 seconds:**
```
7f7f ff69 ce7b 7100 0101 xxxx f7f7
```
The 6th byte increments by 0x0c each packet — an uptime counter. Fixed header `7f7f`, fixed device ID bytes, checksum at end.
---
## Step 3 — What the M1 is doing
The M1 runs on an **ESP32 chip** and implements **Espressif ESP-MESH protocol**. It continuously broadcasts `join_me_req` looking for a mesh root/gateway node. Key identifiers:
- `vendor_id: 45324` — FoxESS-specific identifier
- `mesh_id: 24` — mesh network ID
In a normal M1 installation this mesh root would be the **FoxESS M1 gateway/hub device**. Without it, the M1 loops forever broadcasting join requests and never sends solar data locally.
**There is no local API.** The M1 does not expose any queryable interface over WiFi.
---
## Step 4 — Cloud connection analysis
Despite having no gateway, the M1 does eventually establish an outbound TCP connection to a FoxESS cloud server on a non-standard high port. This connection carries encrypted data — likely TLS. The M1 also repeatedly attempts TCP connections to a secondary IP (192.168.1.1) on port 6666 which never succeeds in my setup.
The M1 also ARPs directly for the cloud server's IP address rather than routing via its default gateway — this appears to be a firmware bug or quirk where it treats the cloud server IP as if it were on the local subnet. This means it can only reach the cloud if it happens to get an ARP reply, which normally comes from the FoxESS hub acting as a mesh root and providing connectivity.
---
## Conclusions
1. **The M1 has no local API** — no Modbus TCP, no HTTP, nothing inbound
2. **ESP-MESH is the local protocol** — the M1 is designed to join a mesh network rooted at a FoxESS hub device
3. **Solar data only flows after mesh join** — until `join_me_req` gets a `join_me_resp`, no data packets are sent
4. **The hub is the key** — whoever has an M1 gateway/hub device and can capture what it sends back as `join_me_resp` holds the answer to local integration
5. **Cloud traffic is encrypted** — intercepting the cloud connection is not a practical path
---
## Questions for the community
1. Does anyone own the **FoxESS M1 hub/gateway device**? Can you capture what it sends back to the M1 on port 6364 as a `join_me_resp`?
2. Has anyone found `vendor_id: 45324` or `mesh_id: 24` in any ESP-MESH open source project?
3. Does the M1 hub expose a local HTTP or Modbus interface once the mesh is established?
If someone can capture the hub's response, it should be possible to build a software mesh root — either a Python script or an ESP32 board — that impersonates the hub and receives the M1's solar data locally without any FoxESS cloud involvement.
Happy to share full tcpdump output if useful.
Thanks