Skip to content

Commit

Permalink
refactor to obtain device information by returning a struct and addin…
Browse files Browse the repository at this point in the history
…g the device id
  • Loading branch information
Dennis Jekubczyk committed May 15, 2022
1 parent 0c88135 commit ad89a23
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 64 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ import (
func main() {
h := hs100.NewHs100("YOUR_HS100_DEVICE", configuration.Default())

name, err := h.GetName()
info, err := h.GetInfo()
if err != nil {
println("Error on accessing device")
os.Exit(1)
}

println("Name of device: " + name)
println("Name of device: " + info.Name)
}
```

Expand Down Expand Up @@ -80,8 +80,8 @@ func main() {

log.Printf("Found devices: %d", len(devices))
for _, d := range devices {
name, _ := d.GetName()
log.Printf("Device name: %s", name)
info, _ := d.GetInfo()
log.Printf("Found device (name, id): %s, %s", info.Name, info.DeviceId)
}
}
```
Expand Down
20 changes: 6 additions & 14 deletions Taskfile.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
version: '2'
version: '3'

silent: true

tasks:
verify:
silent: true
cmds:
- which docker 12> /dev/null
- which go 12> /dev/null
Expand All @@ -11,18 +12,15 @@ tasks:
- docker version >> /dev/null || (echo 'docker daemon is not running' && exit 1)

install-tools:
silent: true
cmds:
- "$(cd $HOME && curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.46.1)"
- "$(go install github.com/mattn/goveralls@latest)"

install:
silent: true
cmds:
- go mod download

world:
silent: true
cmds:
- task: verify
- task: test
Expand All @@ -32,12 +30,10 @@ tasks:

test:
deps: [stop-device-simulation-container]
silent: true
cmds:
- go test -covermode=count -coverprofile=coverage.out $(go list ./... | grep -v '/test/integration') -count=1

integration-test:
silent: true
cmds:
- task: build-device-simulation-image
- task: start-device-simulation-container
Expand All @@ -46,39 +42,35 @@ tasks:

build-device-simulation-image:
dir: test/device-simulation
silent: true
cmds:
- docker image build -t golang-tplink-hs100:device-simulation . >> /dev/null

start-device-simulation-container:
deps: [stop-device-simulation-container]
silent: true
cmds:
- docker container run -e DEBUG=* -p 9999:9999 --name tplink-device-simulation --rm -d golang-tplink-hs100:device-simulation >> /dev/null

stop-device-simulation-container:
silent: true
cmds:
- docker container rm -f tplink-device-simulation &>> /dev/null || true

lint:
silent: true
cmds:
- golangci-lint run

cleanup:
silent: true
cmds:
- go mod verify
- go mod tidy

coveralls-analysis:
silent: true
cmds:
- goveralls -coverprofile=coverage.out -service=github

sonar-analysis:
silent: true
cmds:
- gover
- sonar-scanner

default:
cmds: [ task: world ]
4 changes: 2 additions & 2 deletions cmd/discover/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func main() {

log.Printf("Found devices: %d", len(devices))
for _, d := range devices {
name, _ := d.GetName()
log.Printf("Device name: %s", name)
info, _ := d.GetInfo()
log.Printf("Found device (name, id): %s, %s", info.Name, info.DeviceId)
}
}
4 changes: 2 additions & 2 deletions cmd/show-name/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (
func main() {
h := hs100.NewHs100("192.168.2.100", configuration.Default())

name, err := h.GetName()
info, err := h.GetInfo()
if err != nil {
log.Print("Error on accessing device")
os.Exit(1)
}

log.Printf("Name of device: %s", name)
log.Printf("Name of device: %s", info.Name)
}
62 changes: 34 additions & 28 deletions pkg/hs100/hs100.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ const turnOffCommand = `{"system":{"set_relay_state":{"state":0}}}`
const isOnCommand = `{"system":{"get_sysinfo":{}}}`
const currentPowerConsumptionCommand = `{"emeter":{"get_realtime":{},"get_vgain_igain":{}}}`

type Info struct {
Name string
DeviceId string
on bool
}

type Hs100 struct {
Address string
commandSender CommandSender
Expand Down Expand Up @@ -77,55 +83,47 @@ func (hs100 *Hs100) TurnOff() error {
}

func (hs100 *Hs100) IsOn() (bool, error) {
resp, err := hs100.commandSender.SendCommand(hs100.Address, isOnCommand)
if err != nil {
return false, err
}

err, on := isOn(resp)
if err != nil {
if info, err := hs100.GetInfo(); err != nil {
return false, err
} else {
return info.on, nil
}

return on, nil
}

func isOn(s string) (error, bool) {
var r response
err := json.Unmarshal([]byte(s), &r)
on := r.System.SystemInfo.RelayState == 1
return err, on
}

type response struct {
System struct {
SystemInfo struct {
RelayState int `json:"relay_state"`
Alias string `json:"alias"`
DeviceId string `json:"deviceId"`
} `json:"get_sysinfo"`
} `json:"system"`
}

func (hs100 *Hs100) GetName() (string, error) {
resp, err := hs100.commandSender.SendCommand(hs100.Address, isOnCommand)
// Deprecated:
// Use GetInfo() instead

func (hs100 *Hs100) GetName() (string, error) {
info, err := hs100.GetInfo()
if err != nil {
return "", err
} else {
return info.Name, nil
}

err, name := name(resp)
if err != nil {
return "", err
}

return name, nil
}

func name(resp string) (error, string) {
func toInfo(resp string) (*Info, error) {
var r response
err := json.Unmarshal([]byte(resp), &r)
name := r.System.SystemInfo.Alias
return err, name
if err != nil {
return nil, err
}

return &Info{
Name: r.System.SystemInfo.Alias,
DeviceId: r.System.SystemInfo.DeviceId,
on: r.System.SystemInfo.RelayState == 1,
}, nil
}

func (hs100 *Hs100) GetCurrentPowerConsumption() (PowerConsumption, error) {
Expand All @@ -136,6 +134,14 @@ func (hs100 *Hs100) GetCurrentPowerConsumption() (PowerConsumption, error) {
return powerConsumption(resp)
}

func (hs100 *Hs100) GetInfo() (*Info, error) {
if resp, err := hs100.commandSender.SendCommand(hs100.Address, isOnCommand); err != nil {
return nil, err
} else {
return toInfo(resp)
}
}

type PowerConsumption struct {
Current float32
Voltage float32
Expand Down
70 changes: 56 additions & 14 deletions pkg/hs100/hs100_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
var _ = Describe("Hs100", func() {
const anIpAddress = "192.168.2.1"
const aDeviceName = "some-device-name"
const aDeviceId = "a-device-id"

Describe("turnOn", func() {
const turnOnCommand = `{"system":{"set_relay_state":{"state":1}}}`
Expand Down Expand Up @@ -158,7 +159,7 @@ var _ = Describe("Hs100", func() {
Describe("GetName", func() {
It("read the device name", func() {
s := &commandSender{
response: reponseWithName(aDeviceName),
response: infoResponse(aDeviceName, aDeviceId),
}
hs100 := hs100.NewHs100(anIpAddress, s)

Expand Down Expand Up @@ -194,6 +195,47 @@ var _ = Describe("Hs100", func() {
})
})

Describe("GetDeviceInfo", func() {
It("reads device info", func() {
s := &commandSender{
response: infoResponse(aDeviceName, aDeviceId),
}
hs100 := hs100.NewHs100(anIpAddress, s)

info, err := hs100.GetInfo()

Expect(err).NotTo(HaveOccurred())
assertOneCommandSend(s, anIpAddress, readStateCommand)
Expect(info).NotTo(BeNil())
Expect(info.Name).To(Equal(aDeviceName))
Expect(info.DeviceId).To(Equal(aDeviceId))
})

It("fails if communication with device is not successful", func() {
s := &commandSender{
error: true,
}
hs100 := hs100.NewHs100(anIpAddress, s)

info, err := hs100.GetInfo()

Expect(err).To(HaveOccurred())
Expect(info).To(BeNil())
})

It("fails if response is invalid", func() {
s := &commandSender{
response: "{]",
}
hs100 := hs100.NewHs100(anIpAddress, s)

info, err := hs100.GetInfo()

Expect(err).To(HaveOccurred())
Expect(info).To(BeNil())
})
})

Describe("currentPowerConsumption", func() {
It("reads the current power consumption", func() {
s := &commandSender{
Expand Down Expand Up @@ -254,7 +296,7 @@ var _ = Describe("Hs100", func() {

It("looks up devices", func() {
devices, err := hs100.Discover("192.168.2.0/24", &commandSender{
response: reponseWithName(aDeviceName),
response: infoResponse(aDeviceName, aDeviceId),
})

Expect(err).NotTo(HaveOccurred())
Expand All @@ -274,7 +316,7 @@ var _ = Describe("Hs100", func() {
"192.168.2.30",
"192.168.2.105",
},
response: reponseWithName(aDeviceName),
response: infoResponse(aDeviceName, aDeviceId),
})
Expect(err).NotTo(HaveOccurred())
Expect(len(devices)).To(Equal(3))
Expand All @@ -285,13 +327,13 @@ var _ = Describe("Hs100", func() {

It("discovers in parallel", func() {
start := time.Now()
duration := 10*time.Millisecond
duration := 10 * time.Millisecond
_, err := hs100.Discover("192.168.2.0/24", &commandSender{
response: reponseWithName(aDeviceName),
response: infoResponse(aDeviceName, aDeviceId),
responseDelay: &duration,
})
finished := time.Now()
maximum := start.Add(100*time.Millisecond)
maximum := start.Add(100 * time.Millisecond)

Expect(err).NotTo(HaveOccurred())
Expect(finished.Before(maximum)).To(Equal(true))
Expand Down Expand Up @@ -394,7 +436,7 @@ func offResponse() string {
}`
}

func reponseWithName(name string) string {
func infoResponse(name string, deviceId string) string {
return `{
"system":{
"get_sysinfo":{
Expand All @@ -404,7 +446,7 @@ func reponseWithName(name string) string {
"type":"IOT.SMARTPLUGSWITCH",
"model":"HS110(EU)",
"mac":"AA:BB:CC:DD:EE:FF",
"deviceId":"1234567890123456789012345678901234567890",
"deviceId":"` + deviceId + `",
"hwId":"01234567890123456789012345678912",
"fwId":"98765432109876543210987654321032",
"oemId":"ABCDEFABCDEFABCDEFABCDEFABCDEFAB",
Expand Down Expand Up @@ -432,13 +474,13 @@ func assertOneCommandSend(s *commandSender, address string, command string) {
}

type commandSender struct {
calls int
address string
command string
response string
error bool
calls int
address string
command string
response string
error bool
allowedAddresses *[]string
responseDelay *time.Duration
responseDelay *time.Duration
}

func (c *commandSender) SendCommand(addr string, cmd string) (string, error) {
Expand Down

0 comments on commit ad89a23

Please sign in to comment.