summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorctucx <c@ctu.cx>2020-09-14 13:01:28 +0200
committerctucx <c@ctu.cx>2020-09-14 13:01:28 +0200
commitb9b9e730a25b881e822be8a0ad3ab4c787f99361 (patch)
treef5e6fe7f2014fc2efb1adecda5b7b1e991574b0e
downloadnimtradfri-b9b9e730a25b881e822be8a0ad3ab4c787f99361.tar.gz
nimtradfri-b9b9e730a25b881e822be8a0ad3ab4c787f99361.tar.bz2
nimtradfri-b9b9e730a25b881e822be8a0ad3ab4c787f99361.zip
init
-rw-r--r--coapClient.nim25
-rw-r--r--test.nim16
-rw-r--r--tradfri.nim138
-rw-r--r--types.nim72
4 files changed, 251 insertions, 0 deletions
diff --git a/coapClient.nim b/coapClient.nim
new file mode 100644
index 0000000..e6c75f4
--- /dev/null
+++ b/coapClient.nim
@@ -0,0 +1,25 @@
+import osproc, json
+
+type
+ CoapResponse* = object
+ successful*: bool
+ data*: JsonNode
+ message*: string
+
+
+proc makeCoapRequest* (host: string, port: int, reqMethod: string, user: string, password: string, endpoint: string) :CoapResponse =
+ let reqResult = execProcess("coap-client", args=["-B", "2", "-m", reqMethod, "-u", user, "-k", password, "coaps://" & host & ":" & $port & endpoint], options={poUsePath})
+
+ try:
+ result = CoapResponse(
+ successful: true,
+ data: parseJson(reqResult),
+ message: ""
+ )
+
+ except JsonParsingError:
+ result = CoapResponse(
+ successful: false,
+ data: %* {},
+ message: reqResult
+ )
diff --git a/test.nim b/test.nim
new file mode 100644
index 0000000..c3af19b
--- /dev/null
+++ b/test.nim
@@ -0,0 +1,16 @@
+import types, tradfri, json, tables
+
+let tradfriGateway = newTradfriGateway(
+ host = "192.168.100.225",
+ port = 5684,
+ user = "ctucx",
+ pass = "JrSGx6WkAVJUl53b"
+ )
+
+
+let devices = tradfriGateway.getDevices()
+
+for id, device in devices.pairs:
+ let device = %* device
+
+ echo $id & ": " & pretty device
diff --git a/tradfri.nim b/tradfri.nim
new file mode 100644
index 0000000..4d312dd
--- /dev/null
+++ b/tradfri.nim
@@ -0,0 +1,138 @@
+import json, strutils, tables, options
+
+import coapClient, types
+
+
+proc newTradfrigateway* (host: string, port: int, user: string, pass: string): TradfriGatewayObj =
+ return TradfriGatewayObj(
+ host: host,
+ port: port,
+ user: user,
+ pass: pass
+ )
+
+
+proc parseTradfriDevice (data: JsonNode): TradfriDevice =
+ let deviceType = TradfriDeviceType(data["5750"].getInt)
+ var state: TradfriDeviceState
+
+ case deviceType:
+ of Remote:
+ state = TradfriDeviceState(
+ kind: deviceType,
+ remoteSupported: false
+ )
+
+ of slaveRemote:
+ state = TradfriDeviceState(
+ kind: deviceType,
+ slaveRemoteSupported: false
+ )
+
+ of Lightbulb:
+ state = TradfriDeviceState(
+ kind: deviceType,
+ lightPowered: parseBool($data["3311"][0]["5850"].getInt), # on / off
+ lightBrightness: data["3311"][0]["5851"].getInt # 1 - 254
+ )
+
+ #get hue and saturation (only for RGB-bulbs)
+ if data["3311"][0].hasKey("5707"):
+ state.lightHue = some(data["3311"][0]["5707"].getInt)
+ state.lightSaturation = some(data["3311"][0]["5708"].getInt)
+ else:
+ state.lightHue = none(int)
+ state.lightSaturation = none(int)
+
+
+ #get color hex-value (for white-spectrum and RGB, but only some presets)
+ if data["3311"][0].hasKey("5706"):
+ state.lightColorHex = some(data["3311"][0]["5706"].getStr)
+ else:
+ state.lightColorHex = none(string)
+
+ #get colorX and colorY values (can be used to set any color on RGB bulbs)
+ if data["3311"][0].hasKey("5709"):
+ state.lightColorX = some(data["3311"][0]["5709"].getInt)
+ state.lightColorY = some(data["3311"][0]["5710"].getInt)
+ else:
+ state.lightColorX = none(int)
+ state.lightColorY = none(int)
+
+
+ #get color-specturm value
+ if data["3311"][0].hasKey("5711"):
+ state.lightColorTemperature = some(data["3311"][0]["5711"].getInt)
+ else:
+ state.lightColorTemperature = none(int)
+
+ #determine type of bulb
+ if state.lightHue.isSome:
+ state.lightSpectrum = TradfriLightSpectrum(0)
+ if state.lightColorTemperature.isSome:
+ state.lightSpectrum = TradfriLightSpectrum(1)
+ else:
+ state.lightSpectrum = TradfriLightSpectrum(2)
+
+ of Plug:
+ state = TradfriDeviceState(
+ kind: deviceType,
+ plugPowered: parseBool($data["3312"][0]["5850"].getInt), # on / off
+ plugDimmer: data["3312"][0]["5851"].getInt # 1 - 254 (but currently no dimmable plugs available)
+ )
+
+ of motionSensor:
+ state = TradfriDeviceState(
+ kind: deviceType,
+ motionSensorSupported: false
+ )
+
+ of signalRepeater:
+ state = TradfriDeviceState(
+ kind: deviceType,
+ signalRepeaterSupported: false
+ )
+
+ of Blind:
+ state = TradfriDeviceState(
+ kind: deviceType,
+ blindPosition: data["3"]["5536"].getFloat,
+ blindTrigger: data["3"]["5523"].getFloat
+ )
+
+ of soundRemote:
+ state = TradfriDeviceState(
+ kind: deviceType,
+ soundRemoteSupported: false
+ )
+
+
+ return TradfriDevice(
+ `type`: deviceType,
+ name: data["9001"].getStr,
+ alive: data["9019"].getBool,
+ createdAt: data["9002"].getInt,
+ lastSeen: data["9020"].getInt,
+ instanceId: data["9003"].getInt,
+ state: state,
+ info: TradfriDeviceInfo(
+ manufacturer: data["3"]["0"].getStr,
+ modelNumber: data["3"]["1"].getStr,
+ serialNumber: data["3"]["2"].getStr,
+ firmwareVersion: data["3"]["3"].getStr,
+ power: TradfriPowerSource(data["3"]["6"].getInt),
+ battery: data["3"]{"9"}.getInt
+ )
+ )
+
+proc getDevice* (gatewayObj: TradfriGatewayObj, deviceId: int): TradfriDevice =
+ let resp = makeCoapRequest(gatewayObj.host, gatewayObj.port, "get", gatewayObj.user, gatewayObj.pass, "/15001/" & $deviceId )
+ return parseTradfriDevice(resp.data)
+
+proc getDevices* (gatewayObj: TradfriGatewayObj): Table[int, TradfriDevice] =
+ let resp = makeCoapRequest(gatewayObj.host, gatewayObj.port, "get", gatewayObj.user, gatewayObj.pass, "/15001")
+
+ result = initTable[int, TradfriDevice]()
+
+ for id in resp.data:
+ result.add(id.getInt, getDevice(gatewayObj, id.getInt))
diff --git a/types.nim b/types.nim
new file mode 100644
index 0000000..a34d217
--- /dev/null
+++ b/types.nim
@@ -0,0 +1,72 @@
+import options
+
+type
+ TradfriGatewayObj* = object
+ host*: string
+ port*: int
+ user*: string
+ pass*: string
+
+ TradfriDeviceType* = enum
+ Remote, slaveRemote, Lightbulb, Plug, motionSensor, signalRepeater, Blind, soundRemote
+
+ TradfriPowerSource* = enum
+ Unknown, internalBattery, externalBattery, Battery, POE, USB, AC, Solar
+
+ TradfriLightSpectrum* = enum
+ RGB, White, None
+
+ TradfriDeviceInfo* = object
+ manufacturer*: string
+ modelNumber*: string
+ serialNumber*: string
+ firmwareVersion*: string
+ power*: TradfriPowersource
+ battery*: int
+
+
+ TradfriDeviceState* = object
+ case kind*: TradfriDeviceType
+ of Remote:
+ remoteSupported*: bool
+
+ of slaveRemote:
+ slaveRemoteSupported*: bool
+
+ of Lightbulb:
+ lightPowered*: bool
+ lightSpectrum*: TradfriLightSpectrum
+ lightHue*: Option[int]
+ lightSaturation*: Option[int]
+ lightColorHex*: Option[string]
+ lightColorX*: Option[int]
+ lightColorY*: Option[int]
+ lightColorTemperature*: Option[int]
+ lightBrightness*: int
+
+ of Plug:
+ plugPowered*: bool
+ plugDimmer*: int
+
+ of motionSensor:
+ motionSensorSupported*: bool
+
+ of signalRepeater:
+ signalRepeaterSupported*: bool
+
+ of Blind:
+ blindPosition*: float
+ blindTrigger*: float
+
+ of soundRemote:
+ soundRemoteSupported*: bool
+
+ TradfriDevice* = object
+ `type`*: TradfriDeviceType
+ name*: string
+ alive*: bool
+ createdAt*: int
+ lastSeen*: int
+ instanceId*: int
+ info*: TradfriDeviceInfo
+ state*: TradfriDeviceState