Skip to content

Instantly share code, notes, and snippets.

@fipso
Created April 12, 2025 21:32
Show Gist options
  • Save fipso/aa5a19c85cbb28b50540525d12c65601 to your computer and use it in GitHub Desktop.
Save fipso/aa5a19c85cbb28b50540525d12c65601 to your computer and use it in GitHub Desktop.
directly connect to meross/refoss smart plug. use mitmproxy to get your accounts key
package main
import (
"bytes"
"crypto/md5"
"encoding/json"
"fmt"
"io"
"log"
"math/rand"
"net/http"
"time"
"github.com/davecgh/go-spew/spew"
)
type RefossDeviceConfigHeader struct {
MessageID string `json:"messageId"`
Method string `json:"method"`
From string `json:"from"`
PayloadVersion int `json:"payloadVersion"`
Namespace string `json:"namespace"`
UUID string `json:"uuid"`
Sign string `json:"sign"`
TriggerSrc string `json:"triggerSrc"`
Timestamp int `json:"timestamp"`
}
type RefossDeviceConfigRequest struct {
Header RefossDeviceConfigHeader `json:"header"`
Payload struct {
Electricity RefossDeviceConfigRequestElectricity `json:"electricity"`
} `json:"payload"`
}
type RefossDeviceConfigRequestElectricity struct {
Channel int `json:"channel"`
}
type RefossDeviceConfigResponse struct {
Header RefossDeviceConfigHeader `json:"header"`
Payload struct {
Electricity struct {
Channel int `json:"channel"`
Current int `json:"current"`
Voltage int `json:"voltage"`
Power int `json:"power"`
Config struct {
VoltageRatio int `json:"voltageRatio"`
ElectricityRatio int `json:"electricityRatio"`
MaxElectricityCurrent int `json:"maxElectricityCurrent"`
PowerRatio int `json:"powerRatio"`
} `json:"config"`
} `json:"electricity"`
} `json:"payload"`
}
func pollEnergyDevices() {
for {
for _, device := range config.Refoss_Energy_Devices {
err := pollDevice(device.Address)
if err != nil {
log.Println("Error polling refoss device:", device.Address, err)
}
}
time.Sleep(10 * time.Second)
}
}
// generateRandomString creates a random string of specified length
func generateRandomString(length int) string {
const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
result := make([]byte, length)
for i := range result {
result[i] = charset[rand.Intn(len(charset))]
}
return string(result)
}
// md5Hash generates an MD5 hash of the input string
func md5Hash(input string) string {
hash := md5.Sum([]byte(input))
return fmt.Sprintf("%x", hash)
}
// generateMessageId replicates the g3() function from Java
func generateMessageId() string {
// Initialize random seed
rand.Seed(time.Now().UnixNano())
// Generate random string of 16 chars (k(16))
randomStr := generateRandomString(16)
// Get current timestamp in seconds (m())
timestamp := fmt.Sprintf("%d", time.Now().Unix())
// Combine and hash (g())
return md5Hash(randomStr + timestamp)
}
// generateSign replicates the h3() function from Java
func generateSign(messageId, key, timestamp string) string {
// Concatenate the three parameters and hash
return md5Hash(messageId + key + timestamp)
}
func pollDevice(address string) error {
// Generate timestamp in seconds
timestamp := time.Now().Unix()
// Generate message ID based on the Java implementation
messageId := generateMessageId()
// Generate sign based on the Java implementation
sign := generateSign(messageId, config.Refoss_Key, fmt.Sprintf("%d", timestamp))
reqData := RefossDeviceConfigRequest{
Header: RefossDeviceConfigHeader{
Method: "GET",
From: fmt.Sprintf("%s/config", address),
MessageID: messageId,
PayloadVersion: 1,
Namespace: "Appliance.Control.Electricity",
UUID: "23080400422132510d0448e1e9d4e381",
Sign: sign,
TriggerSrc: "GoClient",
Timestamp: int(timestamp),
},
Payload: struct {
Electricity RefossDeviceConfigRequestElectricity "json:\"electricity\""
}{
Electricity: RefossDeviceConfigRequestElectricity{
Channel: 0,
},
},
}
reqDataJson, err := json.Marshal(reqData)
req, err := http.NewRequest("POST", fmt.Sprintf("%s/config", address), bytes.NewReader(reqDataJson))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Proxy-Connection", "keep-alive")
req.Header.Set("User-Agent", "intellect_socket/1.10.0 (iPhone; iOS 18.3.2; Scale/3.00)")
req.Header.Set("Accept-Language", "en-DE;q=1, de-DE;q=0.9")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
log.Println("Response:", string(body))
var resData RefossDeviceConfigResponse
err = json.Unmarshal(body, &resData)
if err != nil {
return err
}
spew.Dump(resData)
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment