Skip to content

Commit

Permalink
wip: bring fan.go up to spec and add missing rerquest instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
Cian911 committed Mar 29, 2023
1 parent 1b204f7 commit 0fa3ce4
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 17 deletions.
31 changes: 31 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import "github.com/cian911/blauberg-vento/pkg/fan"

const (
LOW_SPEED = "01"
MID_SPEED = "02"
HIGH_SPEED = "03"
)

func main() {
/* f := fan.NewFan(*/
/*"192.168.0.72",*/
/*"004F00384B435705",*/
/*"1111",*/
/*4000,*/
/*)*/

//f.ChangeFanSpeed(HIGH_SPEED)
//f.ChangeFanOperation("invert")

f1 := fan.NewFan(
"192.168.0.238",
"001900284B435704",
"1111",
4000,
)

f1.ChangeFanSpeed(HIGH_SPEED)
}

12 changes: 12 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fans:
- id: "004F00384B435705"
name: "Bedroom"
ipaddress: "192.168.0.172"
password: "1111"
port: 4000

- id: "001900284B435704"
name: "Office"
ipaddress: "192.168.0.238"
password: "1111"
port: 4000
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func main() {

fmt.Println("-----------------------------------")
//encodeData(write_return, on_request, on_value)
encodeData(read, "0093", "")
encodeData(write_return, "00B7", "00")
}

func connect() *net.UDPConn {
Expand Down
4 changes: 3 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package config

func NewConfig() {}
func ParseConfig() {

}
102 changes: 87 additions & 15 deletions pkg/fan/fan.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fan

import (
"encoding/hex"
"errors"
"fmt"
"log"
"net"
Expand All @@ -10,45 +11,108 @@ import (

const PROTOCOL = "udp"

type Fans struct {
Fans []Fan `yaml:"fans"`
}

type Fan struct {
IPAddress string
ID string
Port int
Password string
// Fan IP Address
IPAddress string `yaml:"ipaddress"`
// Fan unique ID
ID string `yaml:"id"`
// Port the fan UDP server runs on - default is 4000
Port int `yaml:"port"`
// Fan password
Password string `yaml:"password"`
// Name of the fan
Name string `yaml:"name"`

conn *net.UDPConn
}

// Create a new Fan
func NewFan(ip_addr, id, pwd string, port int) *Fan {
return &Fan{
fan := &Fan{
IPAddress: ip_addr,
ID: id,
Port: port,
Password: pwd,
}
fan.connect()

return fan
}

// Change fan speed. Possible param values (1..5)
func (f *Fan) ChangeFanSpeed(speed string) string {
data := f.encodedata(OP_WRITE_RETURN_REQUEST, OP_SPEED_MODE_REQUEST, speed)
response := f.send(data)

return response
}

// Change fan operation mode
// Possible params are "in, out, invert"
func (f *Fan) ChangeFanOperation(operation string) string {
op := ""
switch operation {
case "in":
op = OP_AIR_IN
case "out":
op = OP_AIR_OUT
case "invert":
op = OP_AIR_INVERT
default:
log.Println("Fan operation not recognised. Defaulting to invert operation.")
op = OP_AIR_INVERT
}

data := f.encodedata(OP_WRITE_RETURN_REQUEST, OP_AIRFLOW_REQUEST, op)
response := f.send(data)

return response
}

// Connect to fan
func (f *Fan) Connect() {
func (f *Fan) connect() {
server, err := net.ResolveUDPAddr(PROTOCOL, fmt.Sprintf("%s:%d", f.IPAddress, f.Port))
if err != nil {
log.Fatalf("Could not connect to fan (%s) udp server: %v", f.ID, err)
log.Fatalf("Could not connect to fan (%s) udp server: %v", f.Name, err)
}

conn, err := net.DialUDP(PROTOCOL, nil, server)
if err != nil {
log.Fatalf("Could not connect to fan (%s): %v", f.ID, err)
log.Fatalf("Could not connect to fan (%s): %v", f.Name, err)
}

f.conn = conn
}

// Send data to fan
func (f *Fan) Send() {}
// Send and receive data from fan
func (f *Fan) send(data string) string {
payload := f.buildRequestHeaders() + data
payload = HEADER + payload + checksum(payload)
byteData, err := hex.DecodeString(payload)

if err != nil {
log.Fatalf("Could not decode payload data: %v", err)
}

_, err = f.conn.Write(byteData)
if err != nil {
log.Fatalf("Could not write to fan (%s): %v", f.Name, err)
}

bufferedData := make([]byte, 64)
_, err = f.conn.Read(bufferedData)

if err != nil {
log.Fatalf("Could not read response data from fan (%s): %v", f.Name, err)
}

// Receive data from fan
func (f *Fan) Receive() {}
responseStr := string(bufferedData[25:])
return responseStr
}

func (f *Fan) buildRequestHeaders() string {
id_size := getSize(f.ID)
Expand All @@ -69,7 +133,7 @@ func getSize(str string) string {
return fmt.Sprintf("%02d", res)
}

func encodeData(operation, param, value string) string {
func (f *Fan) encodedata(operation, param, value string) string {
out := ""
parameter := ""
val_bytes := 0
Expand Down Expand Up @@ -106,19 +170,27 @@ func encodeData(operation, param, value string) string {

func checksum(msg string) string {
chksum := fmt.Sprintf("%04x", sum(hexToTuple(msg)))
byte_array, _ := hex.DecodeString(chksum)
byte_array, err := hex.DecodeString(chksum)
if err != nil {
log.Fatalf("Could not decode checksum for fan: %v", err)
}
ck := fmt.Sprintf("%02x", byte_array[1]) + fmt.Sprintf("%02x", byte_array[0])
return ck
}

func hexToTuple(msg string) []int64 {
result := []int64{}
val := int64(0)
err := errors.New("")

for i := 0; i < len(msg); i += 2 {
if (i + 2) > len(msg) {
val = 1
} else {
val, _ = strconv.ParseInt(msg[i : (i + 2)], 16, 16)
val, err = strconv.ParseInt(msg[i : (i + 2)], 16, 16)
if err != nil {
log.Fatalf("Could no convert hex to tuple: %v", err)
}
}

result = append(result, val)
Expand Down
8 changes: 8 additions & 0 deletions pkg/fan/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ const (
OP_ON = "01"
OP_OFF = "00"

// Airflow Operations
OP_AIR_OUT = "00"
OP_AIR_INVERT = "01"
OP_AIR_IN = "02"

// Airflow Operation Request
OP_AIRFLOW_REQUEST = "00B7"

// Unit Operation Request
OP_UNIT_OPERATION_REQUEST = "0001"

Expand Down

0 comments on commit 0fa3ce4

Please sign in to comment.