This commit is contained in:
Arnie 2025-11-03 22:13:37 +01:00
commit bf688bf7f8
Signed by: arnie
GPG Key ID: 59315333892F43F4
54 changed files with 3618 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
/log/
/intermediate/
/node_modules/
/output/
/environment.json
.direnv
.devenv
.vscode
.envrc

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
@annex4:registry=https://npm.pkg.github.com
@c3c:registry=https://git.c3c.cz/api/packages/c3c/npm/

37
README.md Normal file
View File

@ -0,0 +1,37 @@
# Control4 KNX Lights
Control4 driver managing the lights system
Notes:
Audio
- any manual action = override ON
Lights
- any manual action = override ON
Presence detected
- turn on lights
Presence detected +10s
- turn on audio
Presence detected +3 min
- Ventilation intake OFF
- Ventilation out 50%
Presence ended
- turn off lights if not overridden
- turn off audio if not overridden
Presence ended + 2 minutes
- turn off lights
- if humidity > 80%, Ventilation intake normal, Ventilation out 100%
- watch humidity on interval, when humidity < 80%, ventilation normal
Presence ended + 5 minutes
- turn off audio if playing
F

1
components/actions.c4c Normal file
View File

@ -0,0 +1 @@
[]

1
components/commands.c4c Normal file
View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,16 @@
[
{
"id": 1,
"connectionname": "KNX Control",
"type": 1,
"consumer": true,
"classes": [
{
"classname": "KNX_DEVICE",
"autobind": false
}
],
"linelevel": true,
"facing": 6
}
]

12
components/events.c4c Normal file
View File

@ -0,0 +1,12 @@
[
{
"id": 100,
"description": "Start Media in Upper Floor Bathroom",
"name": "UpperFloorBathroomMediaStart"
},
{
"id": 101,
"description": "End Media in Upper Floor Bathroom",
"name": "UpperFloorBathroomMediaEnd"
}
]

View File

@ -0,0 +1 @@
[]

12
components/properties.c4c Normal file
View File

@ -0,0 +1,12 @@
[
{
"name": "Log Level",
"type": "DYNAMIC_LIST",
"readonly": false
},
{
"name": "Log Mode",
"type": "DYNAMIC_LIST",
"readonly": false
}
]

7
components/proxies.c4c Normal file
View File

@ -0,0 +1,7 @@
[
{
"id": 5000,
"proxy": "c3c-knx-presence",
"name": "KNX Presence"
}
]

1
components/ui.c4c Normal file
View File

@ -0,0 +1 @@
[]

276
flake.lock Normal file
View File

@ -0,0 +1,276 @@
{
"nodes": {
"cachix": {
"inputs": {
"devenv": [
"nix",
"devenv"
],
"flake-compat": [
"nix",
"devenv"
],
"git-hooks": [
"nix",
"devenv"
],
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1742042642,
"narHash": "sha256-D0gP8srrX0qj+wNYNPdtVJsQuFzIng3q43thnHXQ/es=",
"owner": "cachix",
"repo": "cachix",
"rev": "a624d3eaf4b1d225f918de8543ed739f2f574203",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "latest",
"repo": "cachix",
"type": "github"
}
},
"devenv": {
"inputs": {
"cachix": "cachix",
"flake-compat": "flake-compat",
"git-hooks": "git-hooks",
"nix": "nix_2",
"nixpkgs": [
"nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1744876578,
"narHash": "sha256-8MTBj2REB8t29sIBLpxbR0+AEGJ7f+RkzZPAGsFd40c=",
"owner": "cachix",
"repo": "devenv",
"rev": "7ff7c351bba20d0615be25ecdcbcf79b57b85fe1",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"nix",
"devenv",
"nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": [
"nix",
"devenv"
],
"gitignore": "gitignore",
"nixpkgs": [
"nix",
"devenv",
"nixpkgs"
]
},
"locked": {
"lastModified": 1742649964,
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"nix",
"devenv",
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"libgit2": {
"flake": false,
"locked": {
"lastModified": 1697646580,
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
"owner": "libgit2",
"repo": "libgit2",
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
"type": "github"
},
"original": {
"owner": "libgit2",
"repo": "libgit2",
"type": "github"
}
},
"nix": {
"inputs": {
"devenv": "devenv",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1744882253,
"narHash": "sha256-SHedYfKXqJ0BuB0XDaIbWS0umcqj9ScYTrrWYN8HmMo=",
"ref": "refs/heads/main",
"rev": "49a4dc963156c87f2c13d0ef3db0d8d244bdaa2d",
"revCount": 14,
"type": "git",
"url": "ssh://git@git.c3c.cz/C3C/nix"
},
"original": {
"type": "git",
"url": "ssh://git@git.c3c.cz/C3C/nix"
}
},
"nix_2": {
"inputs": {
"flake-compat": [
"nix",
"devenv"
],
"flake-parts": "flake-parts",
"libgit2": "libgit2",
"nixpkgs": "nixpkgs_2",
"nixpkgs-23-11": [
"nix",
"devenv"
],
"nixpkgs-regression": [
"nix",
"devenv"
],
"pre-commit-hooks": [
"nix",
"devenv"
]
},
"locked": {
"lastModified": 1741798497,
"narHash": "sha256-E3j+3MoY8Y96mG1dUIiLFm2tZmNbRvSiyN7CrSKuAVg=",
"owner": "domenkozar",
"repo": "nix",
"rev": "f3f44b2baaf6c4c6e179de8cbb1cc6db031083cd",
"type": "github"
},
"original": {
"owner": "domenkozar",
"ref": "devenv-2.24",
"repo": "nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1733212471,
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1717432640,
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1744536153,
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nix": "nix"
}
}
},
"root": "root",
"version": 7
}

84
flake.nix Normal file
View File

@ -0,0 +1,84 @@
{
inputs = {
nix.url = "git+ssh://git@git.c3c.cz/C3C/nix";
};
outputs =
{ self, nix }:
{
formatter = nix.formatter;
packages = nix.lib.forAllSystems (pkgs: {
devenv-up = self.devShells.${pkgs.system}.default.config.procfileScript;
devenv-test = self.devShells.${pkgs.system}.default.config.test;
});
devShells = nix.lib.forAllSystems (pkgs: {
default = nix.lib.mkDevenvShell {
inherit pkgs;
inputs = {
self = self;
nixpkgs = pkgs;
};
modules = [
{
packages = [
nix.lib.control4-env.${pkgs.system}
];
scripts = {
menu = {
description = "Print this menu";
exec = ''
echo "Commands:"
echo -n '${
builtins.toJSON (
builtins.mapAttrs (s: value: value.description) self.devShells.${pkgs.system}.default.config.scripts
)
}' | \
${pkgs.jq}/bin/jq -r 'to_entries | map(" \(.key)\n" + " - \(if .value == "" then "no description provided" else .value end)") | "" + .[]'
'';
};
generate = {
exec = ''
${nix.lib.cd_root}
rm -rf ./src/control4-utils
cp -rp node_modules/@c3c/control4-utils/src ./src/control4-utils
node_modules/@c3c/control4-utils/bin/driver-manager ./package.json
mdtohtml -page README.md > src/www/documentation.html
'';
};
github-push = {
description = "Push current branch and all tags to github, lazy workaround for automated mirror. TODO: Automate";
exec = ''
b=$(git rev-parse --abbrev-ref HEAD)
git push git@github.com:Sharsie/control4-knx-presence.git "$b":"$b"
git push git@github.com:Sharsie/control4-knx-presence.git --tags
'';
};
lint = {
exec = ''
${nix.lib.cd_root}
'';
};
fix = {
exec = ''
${nix.lib.cd_root}
nix fmt ./*.nix
stylua ./src
'';
};
};
}
];
};
});
};
}

64
package-lock.json generated Normal file
View File

@ -0,0 +1,64 @@
{
"name": "c3c-knx-presence",
"version": "0.0.223",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "c3c-knx-presence",
"version": "0.0.223",
"hasInstallScript": true,
"license": "GPL-3.0-only",
"devDependencies": {
"@c3c/control4-utils": "^0.5.2",
"@prettier/plugin-lua": "0.0.2",
"prettier": "^3"
}
},
"node_modules/@c3c/control4-utils": {
"version": "0.5.2",
"resolved": "https://git.c3c.cz/api/packages/C3C/npm/%40c3c%2Fcontrol4-utils/-/0.5.2/control4-utils-0.5.2.tgz",
"integrity": "sha512-aKbyjB7SG8mZxYhuBnqngWA1RaFL+3TsH+CDtkOzb4VGZ9VfLk/3a4uvREuClSJMqC6EdrG1t9gz5DTwL2h1Uw==",
"dev": true,
"license": "GPL-3.0-only"
},
"node_modules/@prettier/plugin-lua": {
"version": "0.0.2",
"dev": true,
"license": "MIT",
"dependencies": {
"luaparse": "0.2.1"
},
"engines": {
"node": ">=10.13.0"
},
"peerDependencies": {
"prettier": ">=2.0.0"
}
},
"node_modules/luaparse": {
"version": "0.2.1",
"dev": true,
"license": "MIT",
"bin": {
"luaparse": "bin/luaparse"
}
},
"node_modules/prettier": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
}
}
}

39
package.json Normal file
View File

@ -0,0 +1,39 @@
{
"author": "C3C",
"control4": {
"capabilities": {},
"control": "lua_gen",
"controlmethod": "KNX",
"created": "5/14/2023, 10:16:49 PM",
"icon": {
"image_source": "c4z",
"large": "icons/logo_32.png",
"small": "icons/logo_16.png"
},
"manufacturer": "C3C",
"model": "Presence",
"name": "KNX Presence"
},
"description": "",
"devDependencies": {
"@c3c/control4-utils": "^0.5.2",
"@prettier/plugin-lua": "0.0.2",
"prettier": "^3"
},
"homepage": "https://git.c3c.cz/C3C/control4-knx-presence",
"keywords": [],
"license": "GPL-3.0-only",
"main": "src/driver.lua",
"name": "c3c-knx-presence",
"repository": {
"type": "git",
"url": "https://git.c3c.cz/C3C/control4-knx-presence.git"
},
"scripts": {
"driver-manager": "node_modules/@c3c/control4-utils/bin/driver-manager ./package.json",
"install-control4-utils": "rm -rf ./src/control4-utils && cp -rp node_modules/@c3c/control4-utils/src ./src/control4-utils",
"postinstall": "npm run install-control4-utils && npm run driver-manager",
"test": "busted tests/test.lua"
},
"version": "0.0.223"
}

View File

@ -0,0 +1 @@
C3C = {}

View File

@ -0,0 +1,3 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "helpers.all")

View File

@ -0,0 +1,6 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "context.all")
require(dirRequire .. "logging.all")
require(dirRequire .. "strings.all")
require(dirRequire .. "timers.all")

View File

@ -0,0 +1,36 @@
---@alias C3CContext table<string,string|number|boolean>
do
if not C3C then
print("Control4Utils: ERROR LOADING src.helpers.context.Context, src.base must be required first")
return
end
C3C.Context = {
---@param parentCtx C3CContext
---@param stack string?
---@return C3CContext
Attach = function(parentCtx, stack)
local ctx = {}
for k, v in pairs(parentCtx) do
if type(k) == "string" then
local vt = type(v)
if vt == "string" or vt == "number" or vt == "boolean" then
ctx[k] = v
end
end
end
if not ctx.start then
ctx.start = C4:GetTime()
end
if not ctx.stack then
ctx.stack = ""
elseif stack and stack ~= "" and type(ctx.stack) == "string" then
ctx.stack = ctx.stack .. " -> " .. stack
end
return ctx
end,
}
end

View File

@ -0,0 +1,3 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "Context")

View File

@ -0,0 +1,245 @@
---@alias C3CLogFN fun(s: string): nil
do
if not C3C then
print("Control4Utils: ERROR LOADING src.helpers.logging.Logger, src/base.lua must be required first")
return
end
local logLevelPropName = "Log Level"
local logModePropName = "Log Mode"
local logLevels = ""
local logModes = ""
local defaultLogLevel = "Error"
local defaultLogMode = "Off"
local disableRemotelogging = false
local availableLevels = {
["Debug"] = "debug",
["Error"] = "error",
["Info"] = "info",
}
for k, _ in pairs(availableLevels) do
logLevels = logLevels .. k .. ","
end
logLevels = logLevels:sub(1, -2)
local availableModes = {
["Print"] = "print",
["Log"] = "log",
["Print and Log"] = "printlog",
["Off"] = "off",
}
for k, _ in pairs(availableModes) do
logModes = logModes .. k .. ","
end
logModes = logModes:sub(1, -2)
-- The following functions are helpers for disabling
-- and enabling logging based on mode and log level
local noop = function(s) end
-- Log function is set using the logging mode, to either print
-- or error log into the director
local logFn = noop
-- Print function is set when log leve changes, it internally uses the logFn set by logging mode
local printFn = function(s)
logFn(s)
end
---@type {debug: C3CLogFN, error: C3CLogFN, info: C3CLogFN}
local log = {
debug = noop,
error = noop,
info = noop,
}
--- Sets the logging verbosity
---@param level "Debug"|"Info"|"Error"
local function setLogLevel(level)
if availableLevels[level] == nil then
print(string.format("Invalid logging level requested: %s", level))
return
end
print("Setting log level:" .. level)
if level == "Debug" then
log.debug = printFn
log.info = printFn
log.error = printFn
elseif level == "Error" then
log.debug = noop
log.info = noop
log.error = printFn
elseif level == "Info" then
log.debug = noop
log.info = printFn
log.error = printFn
end
end
--- Sets the target where logging will be sent
---@param mode "Print"|"Log"|"Print and Log"|"Off"
local function setLoggingMode(mode)
if availableModes[mode] == nil then
print(string.format("Invalid logging mode requested: %s", mode))
return
end
print("Setting log mode:" .. mode)
if mode == "Off" then
logFn = noop
elseif mode == "Print" then
logFn = function(s)
print(s)
end
elseif mode == "Log" then
logFn = function(s)
C4:ErrorLog(s)
end
elseif mode == "Print and Log" then
logFn = function(s)
print(s)
C4:ErrorLog(s)
end
end
end
---Formats a table into a string
---@param tParams table
---@return string
local function formatParams(tParams)
tParams = tParams or {}
local out = {}
for k, v in pairs(tParams) do
if type(v) == "string" then
local vString = tostring(v)
if vString:len() > 1000 then
table.insert(out, k .. ': "' .. vString:sub(1, 1000) .. ' [...]"')
else
table.insert(out, k .. ': "' .. vString .. '"')
end
elseif type(v) == "table" then
table.insert(out, k .. ": [" .. formatParams(v) .. "]")
else
table.insert(out, k .. ": " .. tostring(v):sub(1, 100))
end
end
return table.concat(out, ", ")
end
if C3C.HookIntoOnDriverLateInit then
C3C.HookIntoOnDriverLateInit(function()
local logLevel = Properties[logLevelPropName]
local logMode = Properties[logModePropName]
if not logLevel or logLevel == "" then
logLevel = defaultLogLevel
end
if not logMode or logMode == "" then
logMode = defaultLogMode
end
C4:UpdatePropertyList(logLevelPropName, logLevels, logLevel)
C4:UpdatePropertyList(logModePropName, logModes, logMode)
setLogLevel(logLevel)
setLoggingMode(logMode)
end)
else
print("ERROR: HookIntoOnDriverLateInit is not loaded")
end
if C3C.HookIntoOnPropertyChanged then
C3C.HookIntoOnPropertyChanged(function(strProperty)
if strProperty == logLevelPropName then
setLogLevel(Properties[logLevelPropName])
elseif strProperty == logModePropName then
setLoggingMode(Properties[logModePropName])
end
end)
else
print("ERROR: HookIntoOnPropertyChanged is not loaded")
end
C3C.Logger = {
DisableRemoteLogging = function()
disableRemotelogging = true
end,
---Sends the message to a debug channel
---@param s string
---@param ctx table|nil
Debug = function(s, ctx)
local disableRemote = disableRemotelogging
if ctx and ctx.disableRemoteLog == true then
disableRemote = true
ctx.disableRemoteLog = nil
end
if ctx ~= nil then
log.debug("[DEBUG] > " .. s .. " | CTX: " .. formatParams(ctx))
else
log.debug("[DEBUG] > " .. s)
end
if not disableRemote and C3C.RemoteLogger then
local remoteCtx = ctx or {}
remoteCtx.source = "Logger"
C3C.RemoteLogger.Debug(s, remoteCtx)
end
end,
---Sends the message to an error channel
---@param s string
---@param ctx table|nil
Error = function(s, ctx)
local disableRemote = disableRemotelogging
if ctx and ctx.disableRemoteLog == true then
disableRemote = true
ctx.disableRemoteLog = nil
end
if ctx ~= nil then
log.error("[ERROR] > " .. s .. " | CTX: " .. formatParams(ctx))
else
log.error("[ERROR] > " .. s)
end
if not disableRemote and C3C.RemoteLogger then
local remoteCtx = ctx or {}
remoteCtx.source = "Logger"
C3C.RemoteLogger.Error(s, remoteCtx)
end
end,
---Sends the message to an info channel
---@param s string
---@param ctx table|nil
Info = function(s, ctx)
local disableRemote = disableRemotelogging
if ctx and ctx.disableRemoteLog == true then
disableRemote = true
ctx.disableRemoteLog = nil
end
if ctx ~= nil then
log.info("[ INFO] > " .. s .. " | CTX: " .. formatParams(ctx))
else
log.info("[ INFO] > " .. s)
end
if not disableRemote and C3C.RemoteLogger then
local remoteCtx = ctx or {}
remoteCtx.source = "Logger"
C3C.RemoteLogger.Info(s, remoteCtx)
end
end,
}
end

View File

@ -0,0 +1,339 @@
---@alias C3CLogLevel
---|"DEBUG"
---|"INFO"
---|"WARN"
---|"ERROR"
---@alias C3CRemoteLoggerPayload table<string,string|boolean|number>
--- time_of_execution in milliseconds, use C4:GetTime()
---@alias C3CLoggerPayload { level: C3CLogLevel, message: string, service_identifier: string, time_of_execution: number, [string]: string|number|boolean }
---@alias C3CMetricValue string|number|boolean
---@alias C3CMetricPayload { metric: string, service_identifier: string, time_of_execution: number, [string]: C3CMetricValue }
---@alias C3CRemoteLogFN fun(message: string, context: C3CRemoteLoggerPayload): boolean
---@alias C3CMetricFN fun(metric: string, context: C3CRemoteLoggerPayload): boolean
C3CRemoteLoggerCastKeyPrefix = "_cast_"
C3CRemoteLoggerTagKeyPrefix = "_tag_"
C3CRemoteLoggerFieldKeyPrefix = "_field_"
do
if not C3C then
print("Control4Utils: ERROR LOADING src.helpers.logging.RemoteLogger, src/base.lua must be required first")
return
end
local LoggerConnectionBindingID = 100
-- service identifier
---@type string|nil
local SI = nil
---@param payload C3CRemoteLoggerPayload
---@return table<string,string>
local encodeTypedPayload = function(payload)
---@type table<string,string>
local output = {}
local errorCtx = {
level = "ERROR",
message = "Service tried to encode data for remote logger",
}
local error = false
for k, v in pairs(payload) do
if k:sub(1, C3CRemoteLoggerCastKeyPrefix:len()) == C3CRemoteLoggerCastKeyPrefix then
error = true
errorCtx["offending_key_" .. k] = k
end
local vType = type(v)
if vType ~= "nil" and vType ~= "number" and vType ~= "string" and vType ~= "boolean" then
output[k] = "invalid field value type " .. vType
else
output[k] = tostring(v)
if vType ~= "string" then
output[C3CRemoteLoggerCastKeyPrefix .. k] = vType
end
end
end
if error then
C3C.Logger.Error("Tried to remote log data with reserved context keys", errorCtx)
end
return output
end
---@param tags table<string,C3CMetricValue>
---@param fields table<string,C3CMetricValue>
---@return table<string,C3CMetricValue>
local encodeMetrics = function(tags, fields)
---@type table<string,any>
local output = {}
for k, v in pairs(tags) do
output[C3CRemoteLoggerTagKeyPrefix .. k] = v
end
for k, v in pairs(fields) do
output[C3CRemoteLoggerFieldKeyPrefix .. k] = v
end
return output
end
---@param level C3CLogLevel
---@param message string
---@param ctx C3CRemoteLoggerPayload
---@return boolean
local sendLog = function(level, message, ctx)
if SI == nil then
-- Make sure we do not loop
C3C.Logger.Error(
"Tried to remote log without setting up service identifier, call RemoteLogger.Setup first",
{
-- Make sure we do not loop
disableRemoteLog = true,
}
)
return false
end
---@type C3CLoggerPayload
local payload = {
level = "ERROR",
message = "",
service_identifier = SI,
time_of_execution = C4:GetTime(),
}
if ctx.level ~= nil or ctx.message ~= nil or ctx.service_identifier ~= nil or ctx.time_of_execution ~= nil then
C3C.Logger.Error("Tried to remote log data with reserved context keys", {
-- Make sure we do not loop
disableRemoteLog = true,
message = message,
level = level,
ctx = ctx,
})
payload.level = "ERROR"
payload.message = "Service tried to remote log, but used reserved keyword in the context value"
C4:SendToProxy(LoggerConnectionBindingID, "INSERT_LOG", payload, "NOTIFY")
return false
end
payload.level = level
payload.message = message
for k, v in pairs(ctx) do
payload[k] = v
end
C4:SendToProxy(LoggerConnectionBindingID, "INSERT_LOG", encodeTypedPayload(payload), "NOTIFY")
return true
end
---@param metric string
---@param tags table<string,C3CMetricValue>
---@param fields table<string,C3CMetricValue>
---@return boolean
local sendMetric = function(metric, tags, fields)
if SI == nil then
C3C.Logger.Error(
"tried to add remote metric without setting up service identifier, call C3C.RemoteLogger.Setup first",
{
disableRemoteLog = true,
stack = "RemoteLogger.sendMetric",
}
)
return false
end
---@type C3CMetricPayload
local payload = {
metric = metric,
service_identifier = SI,
time_of_execution = C4:GetTime(),
}
if tags.service_identifier ~= nil or tags.time_of_execution ~= nil then
C3C.Logger.Error(
"Tried to add remote metric data with reserved tag keywords",
{ metric = metric, tags = tags }
)
payload.level = "ERROR"
payload.message = "Service tried to add remote metric, but used reserved tag keywords"
C4:SendToProxy(LoggerConnectionBindingID, "INSERT_LOG", payload, "NOTIFY")
return false
end
payload.metric = metric
for k, v in pairs(encodeMetrics(tags, fields)) do
payload[k] = v
end
C4:SendToProxy(LoggerConnectionBindingID, "INSERT_METRIC", encodeTypedPayload(payload), "NOTIFY")
return true
end
C3C.RemoteLogger = {
---@param payload table<string,string>
---@return C3CRemoteLoggerPayload
DecodeUntypedPayload = function(payload)
---@type C3CRemoteLoggerPayload
local output = {}
for k, v in pairs(payload) do
if k:sub(1, C3CRemoteLoggerCastKeyPrefix:len()) ~= C3CRemoteLoggerCastKeyPrefix then
local castValue = payload[C3CRemoteLoggerCastKeyPrefix .. k]
if castValue == "" or castValue == nil then
-- performance
output[k] = v
elseif castValue == "number" then
local numVal = tonumber(v)
if type(numVal) == "number" then
output[k] = numVal
else
output[k] = v
end
elseif castValue == "boolean" then
if v:lower() == "true" or v == "1" then
output[k] = true
else
output[k] = false
end
else
output[k] = v
end
end
end
return output
end,
---@param payload table<string,C3CMetricValue>
---@return {fields: table<string,C3CMetricValue>, tags: table<string,C3CMetricValue>}
DecodeMetrics = function(payload)
---@type {fields: table<string,C3CMetricValue>, tags: table<string,C3CMetricValue>}
local output = {
fields = {},
tags = {},
}
for k, v in pairs(payload) do
if k:sub(1, C3CRemoteLoggerTagKeyPrefix:len()) == C3CRemoteLoggerTagKeyPrefix then
output.tags[k:sub(C3CRemoteLoggerTagKeyPrefix:len() + 1)] = v
elseif k:sub(1, C3CRemoteLoggerFieldKeyPrefix:len()) == C3CRemoteLoggerFieldKeyPrefix then
output.fields[k:sub(C3CRemoteLoggerFieldKeyPrefix:len() + 1)] = v
end
end
return output
end,
---@param service_identifier string
Setup = function(service_identifier)
SI = service_identifier
C4:AddDynamicBinding(
LoggerConnectionBindingID,
"CONTROL",
false,
"Logger",
"c3c-remote-logger",
false,
true
)
end,
---@type C3CRemoteLogFN
Debug = function(message, ctx)
return sendLog("DEBUG", message, ctx)
end,
---@type C3CRemoteLogFN
Info = function(message, ctx)
return sendLog("INFO", message, ctx)
end,
---@type C3CRemoteLogFN
Warn = function(message, ctx)
return sendLog("WARN", message, ctx)
end,
---@type C3CRemoteLogFN
Error = function(message, ctx)
return sendLog("ERROR", message, ctx)
end,
-- Example fields: humidity, temperature, co2
---@param sensorId string
---@param location string
---@param fields table<string,C3CMetricValue>
---@param additionalTags nil|table<string,C3CMetricValue>
AirSensorMetric = function(sensorId, location, fields, additionalTags)
---@type table<string,C3CMetricValue>
local tags = {
sensor_id = sensorId,
location = location,
}
if additionalTags ~= nil then
for k, v in pairs(additionalTags) do
tags[k] = v
end
end
return sendMetric("air_sensor", tags, fields)
end,
-- Example kinds: water_level, door_open
-- Example fields: below_threshold, open
---@param sensorId string
---@param kind string
---@param fields table<string,C3CMetricValue>
---@param additionalTags nil|table<string,C3CMetricValue>
StatusMetric = function(sensorId, kind, fields, additionalTags)
---@type table<string,C3CMetricValue>
local tags = {
sensor_id = sensorId,
kind = kind,
}
if additionalTags ~= nil then
for k, v in pairs(additionalTags) do
tags[k] = v
end
end
return sendMetric("status", tags, fields)
end,
-- Example fields: airflow, boost, setpoint
---@param sensorId string
---@param fields table<string,C3CMetricValue>
---@param additionalTags nil|table<string,C3CMetricValue>
VentilationMetric = function(sensorId, fields, additionalTags)
---@type table<string,C3CMetricValue>
local tags = {
sensor_id = sensorId,
}
if additionalTags ~= nil then
for k, v in pairs(additionalTags) do
tags[k] = v
end
end
return sendMetric("ventilation", tags, fields)
end,
}
end

View File

@ -0,0 +1,4 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "Logger")
require(dirRequire .. "RemoteLogger")

View File

@ -0,0 +1,7 @@
--- Trim whitespace at start and end of string
---@param s string
---@return string, number
function Trim(s) -- Source: PiL2 20.4
s = s or ""
return s:gsub("^%s*(.-)%s*$", "%1")
end

View File

@ -0,0 +1,3 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "Trim")

View File

@ -0,0 +1,43 @@
do
if not C3C then
print("Control4Utils: ERROR LOADING src.helpers.timers.OneShotTimer, src/base.lua must be required first")
return
end
---@type table<string,C4LuaTimer>
local timers = {}
C3C.OneShotTimer = {
ClearAll = function()
for _, timer in pairs(timers) do
timer:Cancel()
end
timers = {}
end,
---@param nDelay number Numeric value in milliseconds which is the desired timer delay. This value must be greater than 0.
---@param fCallback fun(self: C4LuaTimer, skips: number) The function to be called when the timer fires. The function signature for non-repeating timers is: function(timer)
---@param Name string?
Add = function(nDelay, fCallback, Name)
local timer = C4:SetTimer(nDelay, fCallback, false)
-- Look for name if not nil, if found, remove existing timer callback...
if Name ~= nil then
for k, v in pairs(timers) do
if k == Name then
v:Cancel()
timers[k] = nil
end
end
timers[Name] = timer
end
end,
}
if C3C.HookIntoOnDriverLateInit then
C3C.HookIntoOnDriverLateInit(C3C.OneShotTimer.ClearAll)
else
print("hook HookIntoOnDriverLateInit must be loaded")
end
end

View File

@ -0,0 +1,3 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "OneShotTimer")

View File

@ -0,0 +1,3 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "hooks.all")

View File

@ -0,0 +1,30 @@
---@alias C3CExecuteCommandCallback fun(strCommand: string, tParams: table)
do
if not C3C then
print("Control4Utils: ERROR LOADING src.hooks.ExecuteCommand, src/base.lua must be required first")
return
end
-- Stores global hook if already defined
local prevHook
---@type C3CExecuteCommandCallback[]
local hooks = {}
---@param callback C3CExecuteCommandCallback
C3C.HookIntoExecuteCommand = function(callback)
table.insert(hooks, callback)
end
prevHook, ExecuteCommand =
ExecuteCommand or function() end,
---@param strCommand string
---@param tParams table
function(strCommand, tParams)
for _, callback in pairs(hooks) do
callback(strCommand, tParams)
end
prevHook(strCommand, tParams)
end
end

View File

@ -0,0 +1,28 @@
---@alias C3COnDriverLateInitCallback fun(strDIT: string)
do
if not C3C then
print("Control4Utils: ERROR LOADING src.hooks.OnDriverLateInit, src/base.lua must be required first")
return
end
-- Stores global hook if already defined
local prevHook
---@type C3COnDriverLateInitCallback[]
local hooks = {}
---@param callback C3COnDriverLateInitCallback
C3C.HookIntoOnDriverLateInit = function(callback)
table.insert(hooks, callback)
end
prevHook, OnDriverLateInit =
OnDriverLateInit or function() end,
---@param strDIT string
function(strDIT)
for _, callback in pairs(hooks) do
callback(strDIT)
end
prevHook(strDIT)
end
end

View File

@ -0,0 +1,29 @@
---@alias C3COnPropertyChangedCallback fun(strProperty: string)
do
if not C3C then
print("Control4Utils: ERROR LOADING src.hooks.OnPropertyChanged, src/base.lua must be required first")
return
end
-- Stores global hook if already defined
local prevHook
---@type C3COnPropertyChangedCallback[]
local hooks = {}
---@param callback C3COnPropertyChangedCallback
C3C.HookIntoOnPropertyChanged = function(callback)
table.insert(hooks, callback)
end
prevHook, OnPropertyChanged =
OnPropertyChanged or function() end,
---@param strProperty string
function(strProperty)
for _, callback in pairs(hooks) do
callback(strProperty)
end
prevHook(strProperty)
end
end

View File

@ -0,0 +1,31 @@
---@alias C3CReceivedFromProxyCallback fun(idBinding: number, strCommand: string, tParams: table)
do
if not C3C then
print("Control4Utils: ERROR LOADING src.hooks.ReceivedFromProxy, src/base.lua must be required first")
return
end
-- Stores global hook if already defined
local prevHook
---@type C3CReceivedFromProxyCallback[]
local hooks = {}
---@param callback C3CReceivedFromProxyCallback
C3C.HookIntoReceivedFromProxy = function(callback)
table.insert(hooks, callback)
end
prevHook, ReceivedFromProxy =
ReceivedFromProxy or function() end,
---@param idBinding number
---@param strCommand string
---@param tParams table
function(idBinding, strCommand, tParams)
for _, callback in pairs(hooks) do
callback(idBinding, strCommand, tParams)
end
prevHook(idBinding, strCommand, tParams)
end
end

View File

@ -0,0 +1,6 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "ExecuteCommand")
require(dirRequire .. "OnDriverLateInit")
require(dirRequire .. "OnPropertyChanged")
require(dirRequire .. "ReceivedFromProxy")

View File

@ -0,0 +1,3 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "knx.all")

View File

@ -0,0 +1,25 @@
--- @see https://snap-one.github.io/docs-driverworks-knx/#knx-datapoint-type-overview
--- @alias C3CKnxDPT
---|"DPT_1"
---|"DPT_2"
---|"DPT_3"
---|"DPT_4
---|"DPT_5"
---|"DPT_6"
---|"DPT_7"
---|"DPT_8"
---|"DPT_9"
---|"DPT_10"
---|"DPT_11"
---|"DPT_12"
---|"DPT_13"
---|"DPT_14"
---|"DPT_15"
---|"DPT_16"
---|"DPT_17"
---|"DPT_18"
---|"DPT_19"
---|"DPT_5_001"
---|"DPT_232"
---|"DPT_242_600"
---|"DPT_251_600"

View File

@ -0,0 +1,235 @@
---@alias C3CKnxGenericGroupAddressShape<T> { DPT: C3CKnxDPT, GA: string, Name: T, Value: number | nil }
do
if not C3C then
print("Control4Utils: ERROR LOADING src.knx.GroupAddress, src/base.lua must be required first")
return
end
---@param name C3CKnxGroupAddressName
---@param ga string
---@param dpt C3CKnxDPT
C3C.KnxGroupAddress = function(name, ga, dpt)
---@class GroupAddress
---@field DPT C3CKnxDPT
---@field GA string
---@field Name C3CKnxGroupAddressName
---@field Value number|nil
local class = {
DPT = dpt,
GA = ga,
Name = name,
Value = nil,
}
local responding = false
---@param v number
function class:Send(v)
class.Value = v
C3C.KnxProxy.Send(class.DPT, class.GA, class.Value)
end
function class:RespondToRead()
responding = true
end
function class:isResponding()
return responding
end
return class
end
---@type {[C3CKnxGroupAddressName]: GroupAddress}
local namedRegistry = {}
---@type {[string]: GroupAddress|nil}
local addressedRegistry = {}
---@type {[string]: GroupAddress}
local watchedRegistry = {}
---@type {[C3CKnxGroupAddressName]: nil|fun(current: GroupAddress, ctx: { newVal: number, prevVal: number?})[]}
local onChangedRegistry = {}
---@type {[C3CKnxGroupAddressName]: nil|fun(current: GroupAddress, ctx: { newVal: number, prevVal: number?})[]}
local onReceiveRegistry = {}
local registered = false
for _, v in pairs(C3CKnxCreateGroupAddresses()) do
addressedRegistry[v.GA] = v
namedRegistry[v.Name] = v
end
local registerGAs = function()
C3C.KnxProxy.ClearGroupAddresses()
C3C.OneShotTimer.Add(3000, function()
registered = true
for _, g in pairs(watchedRegistry) do
C3C.KnxProxy.AddGroupAddress(g)
end
end, "GroupAddressAddGroupItemsToKnx")
end
C3C.KnxAddresses = {
---Get GroupAddress by name
---@param n C3CKnxGroupAddressName
---@return GroupAddress
Get = function(n)
if namedRegistry[n] == nil then
C3C.Logger.Error(
"error accessing non existing group address name, this should never happen...never",
{ name = n }
)
end
return namedRegistry[n]
end,
---Get GroupAddress by address if defined
---@param ga string
---@return GroupAddress|nil
GetByGA = function(ga)
return addressedRegistry[ga]
end,
---@param n C3CKnxGroupAddressName
---@param onValueReceive nil|fun(current: GroupAddress, state: { newVal: number, prevVal: number? })
---@param onValueChange nil|fun(current: GroupAddress, state: { newVal: number, prevVal: number? })
Watch = function(n, onValueReceive, onValueChange)
if namedRegistry[n] == nil then
C3C.Logger.Error(W
"error accessing non existing group address name to Listen, this should never happen...never",
{ name = n }
)
end
local addr = namedRegistry[n]
watchedRegistry[addr.GA] = addr
if registered then
C3C.OneShotTimer.Add(1000, function()
registerGAs()
end, "knx-register-group-addresses")
end
if onValueReceive ~= nil then
if onReceiveRegistry[addr.GA] == nil then
onReceiveRegistry[addr.GA] = {}
end
table.insert(onReceiveRegistry[addr.GA], onValueReceive)
end
if onValueChange ~= nil then
if onChangedRegistry[addr.GA] == nil then
onChangedRegistry[addr.GA] = {}
end
table.insert(onChangedRegistry[addr.GA], onValueChange)
end
end,
---@param n C3CKnxGroupAddressName
UnWatch = function(n)
local addr = namedRegistry[n]
watchedRegistry[addr.GA] = nil
onReceiveRegistry[addr.GA] = nil
onChangedRegistry[addr.GA] = nil
if registered then
C3C.OneShotTimer.Add(1000, function()
registerGAs()
end, "knx-register-group-addresses")
end
end,
}
C3C.HookIntoOnDriverLateInit(function()
if not C3C.KnxProxy or not C3C.OneShotTimer then
C3C.Logger.Error(
"C3C.KnxProxy or C3C.OneShotTimer is not defined",
{ fn = "control4-utils.knx.GroupADdress HookIntoOnDriverLateInit" }
)
return
end
registerGAs()
end)
C3C.HookIntoExecuteCommand(function(strCommand, tParams)
if not Trim then
C3C.Logger.Error(
"Trim function is not defined",
{ fn = "control4-utils.knx.GroupADdress HookIntoExecuteCommand" }
)
return
end
if strCommand == "KNX_READ_REQUEST" then
local ga = Trim(tParams["GROUP_ADDRESS"])
if ga == "" then
C3C.Logger.Error("received invalid group address from KNX_READ_REQUEST", {
groupAddress = ga,
})
return
end
local addr = C3C.KnxAddresses.GetByGA(ga)
if addr ~= nil and addr.Value ~= nil and addr:isResponding() then
addr:Send(addr.Value)
end
end
if strCommand ~= "DATA_FROM_KNX" then
return
end
local groupAddress = Trim(tParams["GROUP_ADDRESS"])
if groupAddress == "" then
C3C.Logger.Error("received empty group address from DATA_FROM_KNX")
return
end
local addr = C3C.KnxAddresses.GetByGA(groupAddress)
if addr == nil then
C3C.Logger.Error("received unknown group address from DATA_FROM_KNX", {
groupAddress = groupAddress,
})
return
end
local value = nil
if addr.DPT == "DPT_3" then
value = tonumber(tParams["DIRECTION"])
else
value = tonumber(tParams["VALUE"])
end
if value == nil then
C3C.Logger.Error("received invalid data from DATA_FROM_KNX, value is nil", {
groupAddress = groupAddress,
})
return
end
local prevValue = addr.Value
addr.Value = value
if onReceiveRegistry[addr.GA] then
for _, callback in pairs(onReceiveRegistry[addr.GA]) do
callback(addr, { newVal = value, prevVal = prevValue })
end
end
if onChangedRegistry[addr.GA] and prevValue ~= value then
for _, callback in pairs(onChangedRegistry[addr.GA]) do
callback(addr, { newVal = value, prevVal = prevValue })
end
end
end)
end

View File

@ -0,0 +1,68 @@
do
if not C3C then
print("Control4Utils: ERROR LOADING src.knx.Proxy, src/base.lua must be required first")
return
end
local binding = nil
local send = function(strCommand, tParams)
if not binding then
C3C.Logger.Error(
"tried to send data to knx proxy without setting up binding, call C3C.KnxProxy.Setup first",
{
stack = "KnxProxy.send",
}
)
return false
end
local ctx = tParams
ctx.knxCommand = strCommand
C3C.Logger.Debug("sending data to KNX", ctx)
C4:SendToProxy(binding, strCommand, tParams)
end
C3C.KnxProxy = {
---@param bindingId number
Setup = function(bindingId)
binding = bindingId
end,
---@param ga GroupAddress
AddGroupAddress = function(ga)
send("ADD_GROUP_ITEM", {
GROUP_ADDRESS = ga.GA,
DEVICE_ID = C4:GetDeviceID(),
PROPERTY = ga.Name,
DATA_POINT_TYPE = ga.DPT,
})
end,
ClearGroupAddresses = function()
send("CLEAR_GROUP_ITEMS", { DEVICE_ID = C4:GetDeviceID() })
end,
---@param dpt C3CKnxDPT
---@param groupAddress string
---@param value number
Send = function(dpt, groupAddress, value)
local tParams = {}
tParams.DATA_POINT_TYPE = dpt
tParams.GROUP_ADDRESS = groupAddress
tParams.VALUE = value
send("SEND_TO_KNX", tParams)
end,
---@param groupAddress string
Read = function(groupAddress)
local tParams = {}
tParams.GROUP_ADDRESS = groupAddress
send("REQUEST_STATUS", tParams)
end,
}
end

View File

@ -0,0 +1,7 @@
local dirRequire = (...):match("(.-)[^%.%/]+$")
require(dirRequire .. "DPT")
require(dirRequire .. "gen.ADDRESSES")
require(dirRequire .. "gen.createGroupAddresses")
require(dirRequire .. "GroupAddress")
require(dirRequire .. "Proxy")

View File

@ -0,0 +1,927 @@
---@alias C3CKnxGroupAddressName
---|C3CKnxGroupAddressNameControl
---|C3CKnxGroupAddressNameDimmer
---|C3CKnxGroupAddressNameHeat
---|C3CKnxGroupAddressNameMedia
---|C3CKnxGroupAddressNameOther
---|C3CKnxGroupAddressNameScene
---|C3CKnxGroupAddressNameSwitch
---|C3CKnxGroupAddressNameVent
---@alias C3CKnxGroupAddressNameControl
---|"Control LF Hallway Presence"
---|"Control LF Hallway Presence Enable"
---|"Control LF Hallway Presence Enable Workaround"
---|"Control LF Hallway Presence Alarm"
---|"Control LF Hallway Presence Alarm State"
---|"Control LF Study LED Brightness Night"
---|"Control UF Bathroom Presence"
---|"Control UF Bathroom Presence Enable"
---|"Control UF Bathroom Presence Delayed"
---|"Control UF Bathroom Brightness"
---@alias C3CKnxGroupAddressNameDimmer
--- Hallway Primary
---|"Dimmer LF Hallway"
--- Hallway Primary
---|"Dimmer LF Hallway FB"
--- Hallway Primary
---|"Dimmer LF Hallway Dimmer"
---|"Dimmer LF Hallway Color"
---|"Dimmer LF Hallway Color FB"
---|"Dimmer LF Hallway Color Dimmer"
--- Bathroom Primary
---|"Dimmer LF Bathroom Primary"
--- Bathroom Primary
---|"Dimmer LF Bathroom Primary FB"
--- Bathroom Primary
---|"Dimmer LF Bathroom Primary Dimmer"
---|"Dimmer LF Bathroom Primary Color"
---|"Dimmer LF Bathroom Primary Color FB"
---|"Dimmer LF Bathroom Primary Color Dimmer"
--- Bathroom Ambient
--- HAS UNKNOWN DPT
---|"Dimmer LF Bathroom Ambient"
--- Bathroom Ambient
--- HAS UNKNOWN DPT
---|"Dimmer LF Bathroom Ambient FB"
--- Bathroom Ambient
---|"Dimmer LF Bathroom Ambient Dimmer"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bathroom Ambient HSV"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bathroom Ambient HSV FB"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bathroom Ambient Hue Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bathroom Ambient Saturation Dimming"
--- Bathroom Vanity
---|"Dimmer LF Bathroom Vanity"
--- Bathroom Vanity
---|"Dimmer LF Bathroom Vanity FB"
--- Bathroom Vanity
---|"Dimmer LF Bathroom Vanity Dimmer"
---|"Dimmer LF Bathroom Vanity Color"
---|"Dimmer LF Bathroom Vanity Color FB"
---|"Dimmer LF Bathroom Vanity Color Dimmer"
--- Laundry Primary
---|"Dimmer LF Laundry Primary"
--- Laundry Primary
---|"Dimmer LF Laundry Primary FB"
--- Laundry Primary
---|"Dimmer LF Laundry Primary Dimmer"
---|"Dimmer LF Laundry Color"
---|"Dimmer LF Laundry Color FB"
---|"Dimmer LF Laundry Color Dimmer"
--- Bedroom 1 Primary
---|"Dimmer LF Bedroom 1 Primary"
--- Bedroom 1 Primary
---|"Dimmer LF Bedroom 1 Primary FB"
--- Bedroom 1 Primary
---|"Dimmer LF Bedroom 1 Primary Dimmer"
---|"Dimmer LF Bedroom 1 Primary Color"
---|"Dimmer LF Bedroom 1 Primary Color FB"
---|"Dimmer LF Bedroom 1 Primary Color Dimmer"
--- Bedroom 1 Ambient
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 1 Ambient"
--- Bedroom 1 Ambient
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 1 Ambient FB"
--- Bedroom 1 Ambient
---|"Dimmer LF Bedroom 1 Ambient Dimmer"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 1 Ambient HSV"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 1 Ambient HSV FB"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 1 Ambient Hue Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 1 Ambient Saturation Dimming"
--- Study Primary
---|"Dimmer LF Study Primary"
--- Study Primary
---|"Dimmer LF Study Primary FB"
--- Study Primary
---|"Dimmer LF Study Primary Dimmer"
---|"Dimmer LF Study Color"
---|"Dimmer LF Study Color FB"
---|"Dimmer LF Study Color Dimmer"
--- Study Ambient
--- HAS UNKNOWN DPT
---|"Dimmer LF Study Ambient"
--- Study Ambient
--- HAS UNKNOWN DPT
---|"Dimmer LF Study Ambient FB"
--- Study Ambient
---|"Dimmer LF Study Ambient Dimmer"
--- HAS UNKNOWN DPT
---|"Dimmer LF Study Ambient HSV"
--- HAS UNKNOWN DPT
---|"Dimmer LF Study Ambient HSV FB"
--- HAS UNKNOWN DPT
---|"Dimmer LF Study Ambient Hue Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer LF Study Ambient Saturation Dimming"
--- Bedroom 2 Primary
---|"Dimmer LF Bedroom 2 Primary"
--- Bedroom 2 Primary
---|"Dimmer LF Bedroom 2 Primary FB"
--- Bedroom 2 Primary
---|"Dimmer LF Bedroom 2 Primary Dimmer"
---|"Dimmer LF Bedroom 2 Primary Color"
---|"Dimmer LF Bedroom 2 Primary Color FB"
---|"Dimmer LF Bedroom 2 Primary Color Dimmer"
--- Bedroom 2 Ambient
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 2 Ambient"
--- Bedroom 2 Ambient
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 2 Ambient FB"
--- Bedroom 2 Ambient
---|"Dimmer LF Bedroom 2 Ambient Dimmer"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 2 Ambient HSV"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 2 Ambient HSV FB"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 2 Ambient Hue Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer LF Bedroom 2 Ambient Saturation Dimming"
--- Utility room Primary
---|"Dimmer LF Utility"
--- Utility room Primary
---|"Dimmer LF Utility FB"
--- Utility room Primary
---|"Dimmer LF Utility Dimmer"
---|"Dimmer LF Utility Color"
---|"Dimmer LF Utility Color FB"
---|"Dimmer LF Utility Color Dimmer"
--- Hallway Entry
---|"Dimmer UF Hallway"
--- Hallway Entry
---|"Dimmer UF Hallway FB"
--- Hallway Entry
---|"Dimmer UF Hallway Dimming"
--- Hallway Entry
---|"Dimmer UF Hallway Color"
--- Hallway Entry
---|"Dimmer UF Hallway Color FB"
--- Hallway Entry
---|"Dimmer UF Hallway Color Dimming"
--- Bathroom Primary
---|"Dimmer UF Bathroom Primary"
--- Bathroom Primary
---|"Dimmer UF Bathroom Primary FB"
--- Bathroom Primary
---|"Dimmer UF Bathroom Primary Dimming"
---|"Dimmer UF Bathroom Primary Color"
---|"Dimmer UF Bathroom Primary Color FB"
---|"Dimmer UF Bathroom Primary Color Dimming"
--- Bathroom Ambient
---|"Dimmer UF Bathroom Ambient"
--- Bathroom Ambient
---|"Dimmer UF Bathroom Ambient FB"
--- Bathroom Ambient
---|"Dimmer UF Bathroom Ambient Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer UF Bathroom Ambient HSV"
--- HAS UNKNOWN DPT
---|"Dimmer UF Bathroom Ambient HSV FB"
---|"Dimmer UF Bathroom Ambient Hue Dimming"
---|"Dimmer UF Bathroom Ambient Saturation Dimming"
--- Bathroom Vanity
---|"Dimmer UF Bathroom Vanity"
--- Bathroom Vanity
---|"Dimmer UF Bathroom Vanity FB"
--- Bathroom Vanity
---|"Dimmer UF Bathroom Vanity Dimming"
---|"Dimmer UF Bathroom Vanity Color"
---|"Dimmer UF Bathroom Vanity Color FB"
---|"Dimmer UF Bathroom Vanity Color Dimming"
--- Bedroom Primary
---|"Dimmer UF Bedroom Primary"
--- Bedroom Primary
---|"Dimmer UF Bedroom Primary FB"
--- Bedroom Primary
---|"Dimmer UF Bedroom Primary Dimming"
---|"Dimmer UF Bedroom Primary Color"
---|"Dimmer UF Bedroom Primary Color FB"
---|"Dimmer UF Bedroom Primary Color Dimming"
--- Bedroom Ambient
---|"Dimmer UF Bedroom Ambient"
--- Bedroom Ambient
--- HAS UNKNOWN DPT
---|"Dimmer UF Bedroom Ambient FB"
--- Bedroom Ambient
---|"Dimmer UF Bedroom Ambient Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer UF Bedroom Ambient HSV"
--- HAS UNKNOWN DPT
---|"Dimmer UF Bedroom Ambient HSV FB"
--- HAS UNKNOWN DPT
---|"Dimmer UF Bedroom Ambient Hue Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer UF Bedroom Ambient Saturation Dimming"
--- Bedroom Closet
---|"Dimmer UF Closet"
--- Bedroom Closet
---|"Dimmer UF Closet FB"
--- Bedroom Closet
---|"Dimmer UF Closet Dimming"
---|"Dimmer UF Closet Color"
---|"Dimmer UF Closet Color FB"
---|"Dimmer UF Closet Color Dimming"
--- Living room Primary
---|"Dimmer UF Living room Primary"
--- Living room Primary
---|"Dimmer UF Living room Primary FB"
--- Living room Primary
---|"Dimmer UF Living room Primary Dimming"
--- Living room Primary
---|"Dimmer UF Living room Primary Color"
--- Living room Primary
---|"Dimmer UF Living room Primary Color FB"
--- Living room Primary
---|"Dimmer UF Living room Primary Color Dimming"
--- Living room Ambient
---|"Dimmer UF Living room Ambient"
--- Living room Ambient
---|"Dimmer UF Living room Ambient FB"
--- Living room Ambient
---|"Dimmer UF Living room Ambient Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer UF Living room Ambient HSV"
--- HAS UNKNOWN DPT
---|"Dimmer UF Living room Ambient HSV FB"
--- Living room Ambient
---|"Dimmer UF Living room Ambient Hue Dimming"
--- Living room Ambient
---|"Dimmer UF Living room Ambient Saturation Dimming"
--- Office Primary
---|"Dimmer UF Office Primary"
--- Office Primary
---|"Dimmer UF Office Primary FB"
--- Office Primary
---|"Dimmer UF Office Primary Dimming"
---|"Dimmer UF Office Color"
---|"Dimmer UF Office Color FB"
---|"Dimmer UF Office Color Dimming"
--- Dining room Primary
---|"Dimmer UF Dining room"
--- Dining room Primary
---|"Dimmer UF Dining room FB"
--- Dining room Primary
---|"Dimmer UF Dining room Dimming"
---|"Dimmer UF Dining Room Color"
---|"Dimmer UF Dining Room Color FB"
---|"Dimmer UF Dining Room Color Dimming"
--- Kitchen Primary
---|"Dimmer UF Kitchen Primary"
--- Kitchen Primary
---|"Dimmer UF Kitchen Primary FB"
--- Kitchen Primary
---|"Dimmer UF Kitchen Primary Dimming"
---|"Dimmer UF Kitchen Primary Color"
---|"Dimmer UF Kitchen Primary Color FB"
---|"Dimmer UF Kitchen Primary Color Dimming"
--- Kitchen Ambient
--- HAS UNKNOWN DPT
---|"Dimmer UF Kitchen Ambient"
--- Kitchen Ambient
--- HAS UNKNOWN DPT
---|"Dimmer UF Kitchen Ambient FB"
--- Kitchen Ambient
--- HAS UNKNOWN DPT
---|"Dimmer UF Kitchen Ambient Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer UF Kitchen Ambient HSV"
--- HAS UNKNOWN DPT
---|"Dimmer UF Kitchen Ambient HSV FB"
--- HAS UNKNOWN DPT
---|"Dimmer UF Kitchen Ambient Hue Dimming"
--- HAS UNKNOWN DPT
---|"Dimmer UF Kitchen Ambient Saturation Dimming"
--- Kitchen Counter
---|"Dimmer UF Kitchen Counter"
--- Kitchen Counter
---|"Dimmer UF Kitchen Counter FB"
--- Kitchen Counter
---|"Dimmer UF Kitchen Counter Dimming"
---|"Dimmer UF Kitchen Counter Color"
---|"Dimmer UF Kitchen Counter Color FB"
---|"Dimmer UF Kitchen Counter Color Dimming"
--- Kitchen Counter
---|"Dimmer UF Pantry"
--- Kitchen Counter
---|"Dimmer UF Pantry FB"
--- Kitchen Counter
---|"Dimmer UF Pantry Dimming"
---|"Dimmer UF Pantry Color"
---|"Dimmer UF Pantry Color FB"
---|"Dimmer UF Pantry Color Dimming"
--- Staircase Primary
--- HAS UNKNOWN DPT
---|"Dimmer Staircase Tree Dimming"
--- Staircase Primary
--- HAS UNKNOWN DPT
---|"Dimmer Staircase Tree Value"
--- Staircase Primary
--- HAS UNKNOWN DPT
---|"Dimmer Staircase Tree Value Feedback"
--- Staircase Primary
--- HAS UNKNOWN DPT
---|"Dimmer Staircase handrail Swtich"
--- Staircase Primary
--- HAS UNKNOWN DPT
---|"Dimmer Staircase handrail Value"
--- Staircase Primary
--- HAS UNKNOWN DPT
---|"Dimmer Staircase handrail Value Feedback"
--- Staircase Primary
--- HAS UNKNOWN DPT
---|"Dimmer Staircase handrail bottom Dimming"
--- Staircase Primary
--- HAS UNKNOWN DPT
---|"Dimmer Staircase handrail bottom Value"
--- Staircase Primary
--- HAS UNKNOWN DPT
---|"Dimmer Staircase handrail bottom Value Feedback"
--- 20_Garden Terrace
--- HAS UNKNOWN DPT
---|"Dimmer EXT Terrace Dimming"
--- 20_Garden Terrace
--- HAS UNKNOWN DPT
---|"Dimmer EXT Terrace Value"
--- 20_Garden Terrace
--- HAS UNKNOWN DPT
---|"Dimmer EXT Terrace Value Feedback"
--- 20_Exterior Entrance
--- HAS UNKNOWN DPT
---|"Dimmer EXT Entrance Value Feedback"
--- 20_Exterior Entrance
--- HAS UNKNOWN DPT
---|"Dimmer EXT Entrance Dimming"
--- 20_Exterior Entrance
--- HAS UNKNOWN DPT
---|"Dimmer EXT Entrance Value"
--- Parking place Primary
--- HAS UNKNOWN DPT
---|"Dimmer Parking place Dimming"
--- Parking place Primary
--- HAS UNKNOWN DPT
---|"Dimmer Parking place Value"
--- Parking place Primary
--- HAS UNKNOWN DPT
---|"Dimmer Parking place Value Feedback"
---@alias C3CKnxGroupAddressNameHeat
---|"Heat LF Hallway Temperature FB"
---|"Heat LF Bathroom Temperature FB"
---|"Heat LF Bathroom Ladder boost"
---|"Heat LF Bathroom Ladder boost FB"
--- HAS UNKNOWN DPT
---|"Heat LF Laundry Temperature FB"
---|"Heat LF Bedroom 1 Temperature FB"
---|"Heat LF Study Temperature FB"
---|"Heat LF Bedroom 2 Temperature FB"
---|"Heat LF Technical Room Temperature FB"
---|"Heat UF Hallway Temperature FB"
---|"Heat UF Bathroom Temperature FB"
---|"Heat UF Bathroom Ladder boost"
---|"Heat UF Bathroom Ladder boost FB"
---|"Heat UF Bedroom Temperature FB"
---|"Heat UF Living Room Temperature FB"
---|"Heat UF Kitchen Temperature FB"
---|"Heat Circulation Pump"
---|"Heat Circulation Pump FB"
---|"Heat Hot Water Circulation State"
---|"Heat Hot Water Circulation Emergency State"
---|"Heat Hot Water Circulation Control Value"
--- Heating = 1
--- Cooling = 0
---|"Heat Heating-Cooling"
--- Heating = 1
--- Cooling = 0
---|"Heat Heating-Cooling State"
--- HAS UNKNOWN DPT
---|"Heat Temperature Setpoint"
--- HAS UNKNOWN DPT
---|"Heat Temperature Setpoint State"
---|"Heat Heating Off lock"
---|"Heat UF+LF Heating Circulation Pump"
---|"Heat UF+LF Heating Circulation Pump State"
---@alias C3CKnxGroupAddressNameMedia
---|"Media UF Bathroom Playing"
---|"Media UF Bathroom Off"
---|"Media UF Bathroom Volume Down"
---|"Media UF Bathroom Volume Up"
---|"Media UF Bathroom Previous"
---|"Media UF Bathroom Next"
---|"Media UF Bathroom Preset Cycle Forward"
---@alias C3CKnxGroupAddressNameOther
---|"Entry"
---|"Exit"
---|"Present"
---|"UF Bathroom Exit"
---|"LF Bathroom Exit"
--- Day = 0
--- Night = 1
---|"Day/Night"
---|"Date"
---|"Time"
---|"Led Intensity"
---|"Retention Tank Water Level Low"
---@alias C3CKnxGroupAddressNameScene
---|"Scene Lower Floor"
---|"Scene Lower Floor Hallway"
---|"Scene Lower Floor Bathroom"
---|"Scene Lower Floor Laundry"
---|"Scene Lower Floor Bedroom 1"
---|"Scene Lower Floor Study"
---|"Scene Lower Floor Bedroom 2"
---|"Scene Lower Floor Technical Room"
---|"Scene Upper Floor"
---|"Scene Upper Floor Hallway"
---|"Scene Upper Floor Bathroom"
---|"Scene Upper Floor Bedroom"
---|"Scene Upper Floor Closet"
---|"Scene Upper Floor Living Room"
---|"Scene Upper Floor Office"
---|"Scene Upper Floor Dining Room"
---|"Scene Upper Floor Kitchen"
---|"Scene Upper Floor Pantry"
---|"Scene Staircase"
---|"Scene Swimming Pool"
---|"Scene Ventilation Valves"
---|"Scene Ventilation Work"
---@alias C3CKnxGroupAddressNameSwitch
--- Hallway Primary
---|"Switch LF Hallway"
--- Hallway Under staircase
---|"Switch LF Hallway CTRL"
--- Hallway Primary
---|"Switch LF Hallway Light 1"
--- Hallway Primary
---|"Switch LF Hallway Light 2"
--- Hallway Under staircase
---|"Switch LF Hallway Light Below staircase"
--- Hallway Primary
---|"Switch LF Hallway FB"
--- Hallway Under staircase
---|"Switch LF Hallway CTRL FB"
--- Hallway Primary
---|"Switch LF Hallway Light 1 FB"
--- Hallway Primary
---|"Switch LF Hallway Light 2 FB"
--- Hallway Under staircase
---|"Switch LF Hallway Light Below staircase FB"
--- Bathroom Primary
---|"Switch LF Bathroom Primary"
--- Bathroom Vanity
---|"Switch LF Bathroom Primary CTRL"
--- Bathroom Primary
---|"Switch LF Bathroom Primary Light 1"
--- Bathroom Primary
---|"Switch LF Bathroom Primary Light 2"
--- Bathroom Vanity
---|"Switch LF Bathroom Primary Light Vanity"
---|"Switch LF Bathroom Primary Ceiling"
--- Bathroom Primary
---|"Switch LF Bathroom Primary FB"
--- Bathroom Vanity
---|"Switch LF Bathroom Primary CTRL FB"
--- Bathroom Primary
---|"Switch LF Bathroom Primary Light 1 FB"
--- Bathroom Primary
---|"Switch LF Bathroom Primary Light 2 FB"
--- Bathroom Vanity
---|"Switch LF Bathroom Primary Light Vanity FB"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient CTRL"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient Light 1"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient Light 2"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient Toilet"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient FB"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient CTRL FB"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient Light 1 FB"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient Light 2 FB"
--- Bathroom Ambient
---|"Switch LF Bathroom Ambient Toilet FB"
--- Laundry Primary
---|"Switch LF Laundry Primary"
--- Laundry Primary
---|"Switch LF Laundry Primary CTRL"
--- Laundry Primary
---|"Switch LF Laundry Primary Light 1"
--- Laundry Primary
---|"Switch LF Laundry Primary Light 2"
--- Laundry Primary
---|"Switch LF Laundry Primary FB"
--- Laundry Primary
---|"Switch LF Laundry Primary CTRL FB"
--- Laundry Primary
---|"Switch LF Laundry Primary Light 1 FB"
--- Laundry Primary
---|"Switch LF Laundry Primary Light 2 FB"
--- Bedroom 1 Primary
---|"Switch LF Bedroom 1 Primary"
--- Bedroom 1 Reading light
---|"Switch LF Bedroom 1 Primary CTRL"
--- Bedroom 1 Primary
---|"Switch LF Bedroom 1 Primary Light 1"
--- Bedroom 1 Primary
---|"Switch LF Bedroom 1 Primary Light 2"
--- Bedroom 1 Reading light
---|"Switch LF Bedroom 1 Primary Light Reading"
--- Bedroom 1 Primary
---|"Switch LF Bedroom 1 Primary FB"
---|"Switch LF Bedroom 1 Primary CTRL FB"
--- Bedroom 1 Primary
---|"Switch LF Bedroom 1 Primary Light 1 FB"
--- Bedroom 1 Primary
---|"Switch LF Bedroom 1 Primary Light 2 FB"
--- Bedroom 1 Reading light
---|"Switch LF Bedroom 1 Primary Light Reading FB"
--- Bedroom 1 Ambient
---|"Switch LF Bedroom 1 Ambient"
--- Bedroom 1 Ambient
---|"Switch LF Bedroom 1 Ambient CTRL"
--- Bedroom 1 Ambient
---|"Switch LF Bedroom 1 Ambient Light 1"
--- Bedroom 1 Ambient
---|"Switch LF Bedroom 1 Ambient Light 2"
--- Bedroom 1 Ambient
---|"Switch LF Bedroom 1 Ambient FB"
--- Bedroom 1 Ambient
---|"Switch LF Bedroom 1 Ambient CTRL FB"
--- Bedroom 1 Ambient
---|"Switch LF Bedroom 1 Ambient Light 1 FB"
--- Bedroom 1 Ambient
---|"Switch LF Bedroom 1 Ambient Light 2 FB"
--- Study Primary
---|"Switch LF Study Primary"
--- Study Primary
---|"Switch LF Study Primary CTRL"
--- Study Primary
---|"Switch LF Study Primary Light 1"
--- Study Primary
---|"Switch LF Study Primary Light 2"
--- Study Primary
---|"Switch LF Study Primary FB"
--- Study Primary
---|"Switch LF Study Primary CTRL FB"
--- Study Primary
---|"Switch LF Study Primary Light 1 FB"
--- Study Primary
---|"Switch LF Study Primary Light 2 FB"
--- Study Ambient
---|"Switch LF Study Ambient"
--- Study Ambient
---|"Switch LF Study Ambient CTRL"
--- Study Ambient
---|"Switch LF Study Ambient Light 1"
--- Study Ambient
---|"Switch LF Study Ambient Light 2"
--- Study Ambient
---|"Switch LF Study Ambient FB"
--- Study Ambient
---|"Switch LF Study Ambient CTRL FB"
--- Study Ambient
---|"Switch LF Study Ambient Light 1 FB"
--- Study Ambient
---|"Switch LF Study Ambient Light 2 FB"
--- Bedroom 2 Primary
---|"Switch LF Bedroom 2 Primary"
--- Bedroom 2 Reading light
---|"Switch LF Bedroom 2 Primary CTRL"
--- Bedroom 2 Primary
---|"Switch LF Bedroom 2 Primary Light 1"
--- Bedroom 2 Primary
---|"Switch LF Bedroom 2 Primary Light 2"
--- Bedroom 2 Reading light
---|"Switch LF Bedroom 2 Primary Light Reading"
--- Bedroom 2 Primary
---|"Switch LF Bedroom 2 Primary FB"
--- Bedroom 2 Reading light
---|"Switch LF Bedroom 2 Primary CTRL FB"
--- Bedroom 2 Primary
---|"Switch LF Bedroom 2 Primary Light 1 FB"
--- Bedroom 2 Primary
---|"Switch LF Bedroom 2 Primary Light 2 FB"
--- Bedroom 2 Reading light
---|"Switch LF Bedroom 2 Primary Light Reading FB"
--- Bedroom 2 Ambient
---|"Switch LF Bedroom 2 Ambient"
--- Bedroom 2 Ambient
---|"Switch LF Bedroom 2 Ambient CTRL"
--- Bedroom 2 Ambient
---|"Switch LF Bedroom 2 Ambient Light 1"
--- Bedroom 2 Ambient
---|"Switch LF Bedroom 2 Ambient Light 2"
--- Bedroom 2 Ambient
---|"Switch LF Bedroom 2 Ambient FB"
--- Bedroom 2 Ambient
---|"Switch LF Bedroom 2 Ambient CTRL FB"
--- Bedroom 2 Ambient
---|"Switch LF Bedroom 2 Ambient Light 1 FB"
--- Bedroom 2 Ambient
---|"Switch LF Bedroom 2 Ambient Light 2 FB"
---|"Switch LF Utility"
---|"Switch LF Utility CTRL"
---|"Switch LF Utility Light 1"
---|"Switch LF Utility Counter"
---|"Switch LF Utility FB"
---|"Switch LF Utility CTRL FB"
---|"Switch LF Utility Light 1 FB"
---|"Switch LF Utility Counter FB"
---|"Switch UF Hallway Entry"
---|"Switch UF Hallway Isle"
---|"Switch UF Hallway CTRL"
---|"Switch UF Hallway Entry 1"
---|"Switch UF Hallway Entry 2"
---|"Switch UF Hallway Isle 1"
---|"Switch UF Hallway Isle 2"
---|"Switch UF Hallway Entry FB"
---|"Switch UF Hallway Isle FB"
---|"Switch UF Hallway CTRL FB"
---|"Switch UF Hallway Entry 1 FB"
---|"Switch UF Hallway Entry 2 FB"
---|"Switch UF Hallway Isle 1 FB"
---|"Switch UF Hallway Isle 2 FB"
---|"Switch UF Bathroom Primary"
---|"Switch UF Bathroom Primary CTRL"
---|"Switch UF Bathroom Primary Light 1"
---|"Switch UF Bathroom Primary Light 2"
---|"Switch UF Bathroom Primary Light Vanity"
---|"Switch UF Bathroom Primary Ceiling"
---|"Switch UF Bathroom Primary FB"
---|"Switch UF Bathroom Primary CTRL FB"
---|"Switch UF Bathroom Primary Light 1 FB"
---|"Switch UF Bathroom Primary Light 2 FB"
---|"Switch UF Bathroom Primary Light Vanity FB"
---|"Switch UF Bathroom Vanity CTRL"
---|"Switch UF Bathroom Vanity CTRL FB"
---|"Switch UF Bathroom Ambient"
---|"Switch UF Bathroom Ambient CTRL"
---|"Switch UF Bathroom Ambient Light 1"
---|"Switch UF Bathroom Ambient Light 2"
---|"Switch UF Bathroom Ambient Toilet"
---|"Switch UF Bathroom Ambient FB"
---|"Switch UF Bathroom Ambient CTRL FB"
---|"Switch UF Bathroom Ambient Light 1 FB"
---|"Switch UF Bathroom Ambient Light 2 FB"
---|"Switch UF Bathroom Ambient Toilet FB"
---|"Switch UF Bedroom Primary"
---|"Switch UF Bedroom Primary CTRL"
---|"Switch UF Bedroom Primary Light 1"
---|"Switch UF Bedroom Primary Light 2"
---|"Switch UF Bedroom Primary Reading 1"
---|"Switch UF Bedroom Primary Reading 2"
---|"Switch UF Bedroom Primary FB"
---|"Switch UF Bedroom Primary CTRL FB"
---|"Switch UF Bedroom Primary Light 1 FB"
---|"Switch UF Bedroom Primary Light 2 FB"
---|"Switch UF Bedroom Primary Reading 1 FB"
---|"Switch UF Bedroom Primary Reading 2 FB"
---|"Switch UF Bedroom Ambient"
---|"Switch UF Bedroom Ambient CTRL"
---|"Switch UF Bedroom Ambient Light 1"
---|"Switch UF Bedroom Ambient Light 2"
---|"Switch UF Bedroom Ambient FB"
---|"Switch UF Bedroom Ambient CTRL FB"
---|"Switch UF Bedroom Ambient Light 1 FB"
---|"Switch UF Bedroom Ambient Light 2 FB"
---|"Switch UF Closet"
---|"Switch UF Closet CTRL"
---|"Switch UF Closet Light 1"
---|"Switch UF Closet Light 2"
---|"Switch UF Closet FB"
---|"Switch UF Closet CTRL FB"
---|"Switch UF Closet Light 1 FB"
---|"Switch UF Closet Light 2 FB"
---|"Switch UF Living room Primary"
---|"Switch UF Living room Primary CTRL"
---|"Switch UF Living room Primary Light 1"
---|"Switch UF Living room Primary Light 2"
---|"Switch UF Living room Primary Light 3"
---|"Switch UF Living room Primary FB"
---|"Switch UF Living room Primary CTRL FB"
---|"Switch UF Living room Primary Light 1 FB"
---|"Switch UF Living room Primary Light 2 FB"
---|"Switch UF Living room Primary Light 3 FB"
---|"Switch UF Living room Ambient"
---|"Switch UF Living room Ambient CTRL"
---|"Switch UF Living room Ambient Light 1"
---|"Switch UF Living room Ambient Light 2"
---|"Switch UF Living room Ambient FB"
---|"Switch UF Living room Ambient CTRL FB"
---|"Switch UF Living room Ambient Light 1 FB"
---|"Switch UF Living room Ambient Light 2 FB"
---|"Switch UF Office Primary"
---|"Switch UF Office Primary CTRL"
---|"Switch UF Office Primary Light 1"
---|"Switch UF Office Primary Light 2"
---|"Switch UF Office Primary FB"
---|"Switch UF Office Primary CTRL FB"
---|"Switch UF Office Primary Light 1 FB"
---|"Switch UF Office Primary Light 2 FB"
---|"Switch UF Dining room"
---|"Switch UF Dining room CTRL"
---|"Switch UF Dining room Light 1"
---|"Switch UF Dining room Light 2"
---|"Switch UF Dining room FB"
---|"Switch UF Dining room CTRL FB"
---|"Switch UF Dining room Light 1 FB"
---|"Switch UF Dining room Light 2 FB"
---|"Switch UF Kitchen Primary"
---|"Switch UF Kitchen Primary CTRL"
---|"Switch UF Kitchen Primary Light 1"
---|"Switch UF Kitchen Primary Light 2"
---|"Switch UF Kitchen Primary Light 3"
---|"Switch UF Kitchen Primary FB"
---|"Switch UF Kitchen Primary CTRL FB"
---|"Switch UF Kitchen Primary Light 1 FB"
---|"Switch UF Kitchen Primary Light 2 FB"
---|"Switch UF Kitchen Primary Light 3 FB"
---|"Switch UF Kitchen Ambient"
---|"Switch UF Kitchen Ambient CTRL"
---|"Switch UF Kitchen Ambient Light 1"
---|"Switch UF Kitchen Ambient Light 2"
---|"Switch UF Kitchen Ambient Light 3"
---|"Switch UF Kitchen Ambient FB"
---|"Switch UF Kitchen Ambient CTRL FB"
---|"Switch UF Kitchen Ambient Light 1 FB"
---|"Switch UF Kitchen Ambient Light 2 FB"
---|"Switch UF Kitchen Ambient Light 3 FB"
---|"Switch UF Kitchen Counter"
---|"Switch UF Kitchen Counter CTRL"
---|"Switch UF Kitchen Counter Light 1"
---|"Switch UF Kitchen Counter Light 2"
---|"Switch UF Kitchen Counter Light 3"
---|"Switch UF Kitchen Counter FB"
---|"Switch UF Kitchen Counter CTRL FB"
---|"Switch UF Kitchen Counter Light 1 FB"
---|"Switch UF Kitchen Counter Light 2 FB"
---|"Switch UF Kitchen Counter Light 3 FB"
---|"Switch UF Pantry"
---|"Switch UF Pantry CTRL"
---|"Switch UF Pantry Light 1"
---|"Switch UF Pantry Light 2"
---|"Switch UF Pantry FB"
---|"Switch UF Pantry CTRL FB"
---|"Switch UF Pantry Light 1 FB"
---|"Switch UF Pantry Light 2 FB"
---|"Switch Staircase"
---|"Switch Staircase CTRL"
--- Staircase Primary
---|"Switch Staircase Tree"
--- Staircase Primary
---|"Switch Staircase Handrail"
---|"Switch Staircase FB"
---|"Switch Staircase CTRL FB"
--- Staircase Primary
---|"Switch Staircase Tree FB"
--- Staircase Primary
---|"Switch Staircase Handrail FB"
--- 20_Garden Terrace
---|"Switch EXT Terrace"
--- 20_Garden Terrace
---|"Switch EXT Terrace FB"
--- 20_Exterior Entrance
---|"Switch EXT Entrance"
--- 20_Exterior Entrance
---|"Switch EXT Entrance FB"
--- Parking place Primary
---|"Switch Parking place"
--- Parking place Primary
---|"Switch Parking place FB"
---|"Switch Parking place AC Plug Right of Door"
---|"Switch Parking place AC Plug Right of Door State"
---|"Switch Underwater Light"
---|"Switch Underwater Light FB"
---|"Switch Filtration"
---|"Switch Filtration FB"
---@alias C3CKnxGroupAddressNameVent
--- HAS UNKNOWN DPT
---|"Vent LF PLACEHOLDER Hallway"
---|"Vent LF Hallway Valve IN"
---|"Vent LF Hallway Valve IN FB"
---|"Vent LF Bathroom CO2 FB"
---|"Vent LF Bathroom Humidity FB"
---|"Vent LF Bathroom boost"
---|"Vent LF Bathroom boost FB"
---|"Vent LF Bathroom Valve IN"
---|"Vent LF Bathroom Valve IN FB"
---|"Vent LF Bathroom Valve OUT"
---|"Vent LF Bathroom Valve OUT FB"
--- HAS UNKNOWN DPT
---|"Vent LF PLACEHOLDER Laundry"
---|"Vent LF Bedroom 1 CO2 FB"
---|"Vent LF Bedroom 1 Humidity FB"
---|"Vent LF Bedroom 1 Valve IN"
---|"Vent LF Bedroom 1 Valve IN FB"
---|"Vent LF Study CO2 FB"
---|"Vent LF Study Humidity FB"
---|"Vent LF Study Valve IN"
---|"Vent LF Study Valve IN FB"
---|"Vent LF Study Valve IN Lock"
---|"Vent LF Bedroom 2 CO2 FB"
---|"Vent LF Bedroom 2 Humidity FB"
---|"Vent LF Bedroom 2 Valve IN"
---|"Vent LF Bedroom 2 Valve IN FB"
--- HAS UNKNOWN DPT
---|"Vent LF Technical Room CO2 FB"
---|"Vent LF Technical Room Humidity FB"
---|"Vent LF Box Valve OUT"
---|"Vent LF Box Valve OUT FB"
---|"Vent LF Box Valve OUT Lock"
--- HAS UNKNOWN DPT
---|"Vent UF PLACEHOLDER Hallway"
---|"Vent UF Bathroom CO2 FB"
---|"Vent UF Bathroom Humidity FB"
---|"Vent UF Bathroom boost"
---|"Vent UF Bathroom boost FB"
---|"Vent UF Bathroom Valve IN"
---|"Vent UF Bathroom Valve IN FB"
---|"Vent UF Bathroom Valve IN Lock"
--- HAS UNKNOWN DPT
---|"Vent UF PLACEHOLDER Bedroom"
---|"Vent UF Bedroom Valve IN"
---|"Vent UF Bedroom Valve IN FB"
---|"Vent UF Bedroom Valve IN Lock"
---|"Vent UF Bedroom CO2 FB"
---|"Vent UF Bedroom Humidity FB"
---|"Vent UF Living Room CO2 FB"
---|"Vent UF Living Room Humidity FB"
---|"Vent UF Living Room Valve IN"
---|"Vent UF Living Room Valve IN FB"
--- HAS UNKNOWN DPT
---|"Vent UF PLACEHOLDER Office"
---|"Vent UF Office Valve IN"
---|"Vent UF Office Valve IN FB"
---|"Vent UF Bathroom Valve OUT"
---|"Vent UF Bathroom Valve OUT FB"
---|"Vent UF Bathroom Valve OUT Lock"
--- HAS UNKNOWN DPT
---|"Vent UF PLACEHOLDER Dining Room"
--- HAS UNKNOWN DPT
---|"Vent UF PLACEHOLDER Kitchen"
---|"Vent UF Kitchen Valve OUT"
---|"Vent UF Kitchen Valve OUT FB"
---|"Vent UF Kitchen CO2 FB"
---|"Vent UF Kitchen Humidity FB"
---|"Vent UF Kitchen TVOC FB"
---|"Vent UF Kitchen boost"
---|"Vent UF Kitchen boost FB"
---|"Vent UF Closet+Hallway Valve OUT"
---|"Vent UF Closet+Hallway Valve OUT FB"
---|"Vent UF Closet+Hallway Valve OUT Lock"
---|"Vent Airflow"
---|"Vent Standby FB"
---|"Vent Temperature: Supply"
---|"Vent Temperature: Outdoor"
---|"Vent Temperature: Extract"
---|"Vent Temperature: Exhaust"
---|"Vent Humidity: Supply"
---|"Vent Humidity: Outdoor"
---|"Vent Humidity: Extract"
---|"Vent Humidity: Exhaust"
---|"Vent Filter: Remaining (h)"
---|"Vent Filter: Replace"
---|"Vent Heating-Cooling"
---|"Vent Heating-Cooling State"
---|"Vent Boost"
---|"Vent Boost FB"
---|"Vent Auto mode"
---|"Vent Auto mode FB"
---|"Vent Preset"
---|"Vent Preset FB"
---|"Vent Preset Away"
---|"Vent Preset Away FB"
---|"Vent Away function"
---|"Vent Away function FB"
---|"Vent Temperature profile mode"
---|"Vent Temperature profile mode FB"
---|"Vent Temperature profile"
---|"Vent Temperature profile FB"
---|"Vent Boost Time"
---|"Vent Boost Time FB"
---|"Vent External setpoint"
---|"Vent External setpoint FB"
---|"Vent Error"
---|"Vent Status"

View File

@ -0,0 +1,628 @@
---@return table<number,GroupAddress>
function C3CKnxCreateGroupAddresses()
return {
C3C.KnxGroupAddress("Entry", "0/0/1", "DPT_1"),
C3C.KnxGroupAddress("Exit", "0/0/2", "DPT_1"),
C3C.KnxGroupAddress("Present", "0/0/3", "DPT_1"),
C3C.KnxGroupAddress("UF Bathroom Exit", "0/0/50", "DPT_1"),
C3C.KnxGroupAddress("LF Bathroom Exit", "0/0/100", "DPT_1"),
C3C.KnxGroupAddress("Day/Night", "0/1/0", "DPT_1"),
C3C.KnxGroupAddress("Date", "0/1/1", "DPT_11"),
C3C.KnxGroupAddress("Time", "0/1/2", "DPT_10"),
C3C.KnxGroupAddress("Led Intensity", "0/1/100", "DPT_5"),
C3C.KnxGroupAddress("Retention Tank Water Level Low", "0/1/200", "DPT_1"),
C3C.KnxGroupAddress("Scene Lower Floor", "0/2/100", "DPT_17"),
C3C.KnxGroupAddress("Scene Lower Floor Hallway", "0/2/101", "DPT_17"),
C3C.KnxGroupAddress("Scene Lower Floor Bathroom", "0/2/102", "DPT_17"),
C3C.KnxGroupAddress("Scene Lower Floor Laundry", "0/2/103", "DPT_17"),
C3C.KnxGroupAddress("Scene Lower Floor Bedroom 1", "0/2/104", "DPT_17"),
C3C.KnxGroupAddress("Scene Lower Floor Study", "0/2/105", "DPT_17"),
C3C.KnxGroupAddress("Scene Lower Floor Bedroom 2", "0/2/106", "DPT_17"),
C3C.KnxGroupAddress("Scene Lower Floor Technical Room", "0/2/107", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor", "0/2/150", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor Hallway", "0/2/151", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor Bathroom", "0/2/152", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor Bedroom", "0/2/153", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor Closet", "0/2/154", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor Living Room", "0/2/155", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor Office", "0/2/156", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor Dining Room", "0/2/157", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor Kitchen", "0/2/158", "DPT_17"),
C3C.KnxGroupAddress("Scene Upper Floor Pantry", "0/2/159", "DPT_17"),
C3C.KnxGroupAddress("Scene Staircase", "0/2/200", "DPT_17"),
C3C.KnxGroupAddress("Scene Swimming Pool", "0/2/210", "DPT_17"),
C3C.KnxGroupAddress("Scene Ventilation Valves", "0/2/220", "DPT_17"),
C3C.KnxGroupAddress("Scene Ventilation Work", "0/2/221", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway", "1/0/0", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway CTRL", "1/0/1", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway Light 1", "1/0/2", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway Light 2", "1/0/3", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway Light Below staircase", "1/0/4", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway FB", "1/0/7", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway CTRL FB", "1/0/8", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway Light 1 FB", "1/0/9", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway Light 2 FB", "1/0/10", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Hallway Light Below staircase FB", "1/0/11", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary", "1/0/20", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary CTRL", "1/0/21", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary Light 1", "1/0/22", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary Light 2", "1/0/23", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary Light Vanity", "1/0/24", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary Ceiling", "1/0/25", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary FB", "1/0/27", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary CTRL FB", "1/0/28", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary Light 1 FB", "1/0/29", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary Light 2 FB", "1/0/30", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Primary Light Vanity FB", "1/0/31", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient", "1/0/35", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient CTRL", "1/0/36", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient Light 1", "1/0/37", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient Light 2", "1/0/38", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient Toilet", "1/0/39", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient FB", "1/0/42", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient CTRL FB", "1/0/43", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient Light 1 FB", "1/0/44", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient Light 2 FB", "1/0/45", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bathroom Ambient Toilet FB", "1/0/46", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Laundry Primary", "1/0/70", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Laundry Primary CTRL", "1/0/71", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Laundry Primary Light 1", "1/0/72", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Laundry Primary Light 2", "1/0/73", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Laundry Primary FB", "1/0/77", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Laundry Primary CTRL FB", "1/0/78", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Laundry Primary Light 1 FB", "1/0/79", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Laundry Primary Light 2 FB", "1/0/80", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary", "1/0/90", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary CTRL", "1/0/91", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary Light 1", "1/0/92", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary Light 2", "1/0/93", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary Light Reading", "1/0/94", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary FB", "1/0/97", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary CTRL FB", "1/0/98", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary Light 1 FB", "1/0/99", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary Light 2 FB", "1/0/100", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Primary Light Reading FB", "1/0/101", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Ambient", "1/0/105", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Ambient CTRL", "1/0/106", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Ambient Light 1", "1/0/107", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Ambient Light 2", "1/0/108", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Ambient FB", "1/0/112", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Ambient CTRL FB", "1/0/113", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Ambient Light 1 FB", "1/0/114", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 1 Ambient Light 2 FB", "1/0/115", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Primary", "1/0/140", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Primary CTRL", "1/0/141", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Primary Light 1", "1/0/142", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Primary Light 2", "1/0/143", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Primary FB", "1/0/147", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Primary CTRL FB", "1/0/148", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Primary Light 1 FB", "1/0/149", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Primary Light 2 FB", "1/0/150", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Ambient", "1/0/155", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Ambient CTRL", "1/0/156", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Ambient Light 1", "1/0/157", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Ambient Light 2", "1/0/158", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Ambient FB", "1/0/162", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Ambient CTRL FB", "1/0/163", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Ambient Light 1 FB", "1/0/164", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Study Ambient Light 2 FB", "1/0/165", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary", "1/0/190", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary CTRL", "1/0/191", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary Light 1", "1/0/192", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary Light 2", "1/0/193", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary Light Reading", "1/0/194", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary FB", "1/0/197", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary CTRL FB", "1/0/198", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary Light 1 FB", "1/0/199", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary Light 2 FB", "1/0/200", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Primary Light Reading FB", "1/0/201", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Ambient", "1/0/205", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Ambient CTRL", "1/0/206", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Ambient Light 1", "1/0/207", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Ambient Light 2", "1/0/208", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Ambient FB", "1/0/212", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Ambient CTRL FB", "1/0/213", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Ambient Light 1 FB", "1/0/214", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Bedroom 2 Ambient Light 2 FB", "1/0/215", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Utility", "1/0/225", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Utility CTRL", "1/0/226", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Utility Light 1", "1/0/227", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Utility Counter", "1/0/228", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Utility FB", "1/0/232", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Utility CTRL FB", "1/0/233", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Utility Light 1 FB", "1/0/234", "DPT_1"),
C3C.KnxGroupAddress("Switch LF Utility Counter FB", "1/0/235", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Entry", "1/1/0", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Isle", "1/1/1", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway CTRL", "1/1/2", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Entry 1", "1/1/3", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Entry 2", "1/1/4", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Isle 1", "1/1/5", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Isle 2", "1/1/6", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Entry FB", "1/1/7", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Isle FB", "1/1/8", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway CTRL FB", "1/1/9", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Entry 1 FB", "1/1/10", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Entry 2 FB", "1/1/11", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Isle 1 FB", "1/1/12", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Hallway Isle 2 FB", "1/1/13", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary", "1/1/20", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary CTRL", "1/1/21", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary Light 1", "1/1/22", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary Light 2", "1/1/23", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary Light Vanity", "1/1/24", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary Ceiling", "1/1/25", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary FB", "1/1/27", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary CTRL FB", "1/1/28", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary Light 1 FB", "1/1/29", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary Light 2 FB", "1/1/30", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Primary Light Vanity FB", "1/1/31", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Vanity CTRL", "1/1/33", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Vanity CTRL FB", "1/1/34", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient", "1/1/35", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient CTRL", "1/1/36", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient Light 1", "1/1/37", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient Light 2", "1/1/38", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient Toilet", "1/1/39", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient FB", "1/1/42", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient CTRL FB", "1/1/43", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient Light 1 FB", "1/1/44", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient Light 2 FB", "1/1/45", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bathroom Ambient Toilet FB", "1/1/46", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary", "1/1/50", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary CTRL", "1/1/51", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary Light 1", "1/1/52", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary Light 2", "1/1/53", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary Reading 1", "1/1/54", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary Reading 2", "1/1/55", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary FB", "1/1/57", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary CTRL FB", "1/1/58", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary Light 1 FB", "1/1/59", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary Light 2 FB", "1/1/60", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary Reading 1 FB", "1/1/61", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Primary Reading 2 FB", "1/1/62", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Ambient", "1/1/65", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Ambient CTRL", "1/1/66", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Ambient Light 1", "1/1/67", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Ambient Light 2", "1/1/68", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Ambient FB", "1/1/72", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Ambient CTRL FB", "1/1/73", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Ambient Light 1 FB", "1/1/74", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Bedroom Ambient Light 2 FB", "1/1/75", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Closet", "1/1/80", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Closet CTRL", "1/1/81", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Closet Light 1", "1/1/82", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Closet Light 2", "1/1/83", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Closet FB", "1/1/87", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Closet CTRL FB", "1/1/88", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Closet Light 1 FB", "1/1/89", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Closet Light 2 FB", "1/1/90", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary", "1/1/95", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary CTRL", "1/1/96", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary Light 1", "1/1/97", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary Light 2", "1/1/98", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary Light 3", "1/1/99", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary FB", "1/1/102", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary CTRL FB", "1/1/103", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary Light 1 FB", "1/1/104", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary Light 2 FB", "1/1/105", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Primary Light 3 FB", "1/1/106", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Ambient", "1/1/110", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Ambient CTRL", "1/1/111", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Ambient Light 1", "1/1/112", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Ambient Light 2", "1/1/113", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Ambient FB", "1/1/117", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Ambient CTRL FB", "1/1/118", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Ambient Light 1 FB", "1/1/119", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Living room Ambient Light 2 FB", "1/1/120", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Office Primary", "1/1/125", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Office Primary CTRL", "1/1/126", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Office Primary Light 1", "1/1/127", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Office Primary Light 2", "1/1/128", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Office Primary FB", "1/1/132", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Office Primary CTRL FB", "1/1/133", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Office Primary Light 1 FB", "1/1/134", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Office Primary Light 2 FB", "1/1/135", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Dining room", "1/1/140", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Dining room CTRL", "1/1/141", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Dining room Light 1", "1/1/142", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Dining room Light 2", "1/1/143", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Dining room FB", "1/1/147", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Dining room CTRL FB", "1/1/148", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Dining room Light 1 FB", "1/1/149", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Dining room Light 2 FB", "1/1/150", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary", "1/1/155", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary CTRL", "1/1/156", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary Light 1", "1/1/157", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary Light 2", "1/1/158", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary Light 3", "1/1/159", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary FB", "1/1/162", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary CTRL FB", "1/1/163", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary Light 1 FB", "1/1/164", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary Light 2 FB", "1/1/165", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Primary Light 3 FB", "1/1/166", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient", "1/1/170", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient CTRL", "1/1/171", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient Light 1", "1/1/172", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient Light 2", "1/1/173", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient Light 3", "1/1/174", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient FB", "1/1/177", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient CTRL FB", "1/1/178", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient Light 1 FB", "1/1/179", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient Light 2 FB", "1/1/180", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Ambient Light 3 FB", "1/1/181", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter", "1/1/185", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter CTRL", "1/1/186", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter Light 1", "1/1/187", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter Light 2", "1/1/188", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter Light 3", "1/1/189", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter FB", "1/1/192", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter CTRL FB", "1/1/193", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter Light 1 FB", "1/1/194", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter Light 2 FB", "1/1/195", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Kitchen Counter Light 3 FB", "1/1/196", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Pantry", "1/1/200", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Pantry CTRL", "1/1/201", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Pantry Light 1", "1/1/202", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Pantry Light 2", "1/1/203", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Pantry FB", "1/1/207", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Pantry CTRL FB", "1/1/208", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Pantry Light 1 FB", "1/1/209", "DPT_1"),
C3C.KnxGroupAddress("Switch UF Pantry Light 2 FB", "1/1/210", "DPT_1"),
C3C.KnxGroupAddress("Switch Staircase", "1/2/0", "DPT_1"),
C3C.KnxGroupAddress("Switch Staircase CTRL", "1/2/1", "DPT_1"),
C3C.KnxGroupAddress("Switch Staircase Tree", "1/2/2", "DPT_1"),
C3C.KnxGroupAddress("Switch Staircase Handrail", "1/2/3", "DPT_1"),
C3C.KnxGroupAddress("Switch Staircase FB", "1/2/7", "DPT_1"),
C3C.KnxGroupAddress("Switch Staircase CTRL FB", "1/2/8", "DPT_1"),
C3C.KnxGroupAddress("Switch Staircase Tree FB", "1/2/9", "DPT_1"),
C3C.KnxGroupAddress("Switch Staircase Handrail FB", "1/2/10", "DPT_1"),
C3C.KnxGroupAddress("Switch EXT Terrace", "1/3/0", "DPT_1"),
C3C.KnxGroupAddress("Switch EXT Terrace FB", "1/3/7", "DPT_1"),
C3C.KnxGroupAddress("Switch EXT Entrance", "1/3/20", "DPT_1"),
C3C.KnxGroupAddress("Switch EXT Entrance FB", "1/3/27", "DPT_1"),
C3C.KnxGroupAddress("Switch Parking place", "1/4/0", "DPT_1"),
C3C.KnxGroupAddress("Switch Parking place FB", "1/4/7", "DPT_1"),
C3C.KnxGroupAddress("Switch Parking place AC Plug Right of Door", "1/4/10", "DPT_1"),
C3C.KnxGroupAddress("Switch Parking place AC Plug Right of Door State", "1/4/17", "DPT_1"),
C3C.KnxGroupAddress("Switch Underwater Light", "1/5/0", "DPT_1"),
C3C.KnxGroupAddress("Switch Underwater Light FB", "1/5/1", "DPT_1"),
C3C.KnxGroupAddress("Switch Filtration", "1/5/10", "DPT_1"),
C3C.KnxGroupAddress("Switch Filtration FB", "1/5/11", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Hallway", "2/0/0", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Hallway FB", "2/0/1", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Hallway Dimmer", "2/0/2", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Hallway Color", "2/0/5", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Hallway Color FB", "2/0/6", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Hallway Color Dimmer", "2/0/7", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Primary", "2/0/20", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Primary FB", "2/0/21", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Primary Dimmer", "2/0/22", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Primary Color", "2/0/25", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Primary Color FB", "2/0/26", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Primary Color Dimmer", "2/0/27", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Ambient", "2/0/35", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Ambient FB", "2/0/36", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Ambient Dimmer", "2/0/37", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Ambient HSV", "2/0/40", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Ambient HSV FB", "2/0/41", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Ambient Hue Dimming", "2/0/42", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Ambient Saturation Dimming", "2/0/43", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Vanity", "2/0/50", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Vanity FB", "2/0/51", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Vanity Dimmer", "2/0/52", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Vanity Color", "2/0/53", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Vanity Color FB", "2/0/54", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bathroom Vanity Color Dimmer", "2/0/55", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Laundry Primary", "2/0/70", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Laundry Primary FB", "2/0/71", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Laundry Primary Dimmer", "2/0/72", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Laundry Color", "2/0/75", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Laundry Color FB", "2/0/76", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Laundry Color Dimmer", "2/0/77", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Primary", "2/0/90", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Primary FB", "2/0/91", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Primary Dimmer", "2/0/92", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Primary Color", "2/0/95", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Primary Color FB", "2/0/96", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Primary Color Dimmer", "2/0/97", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Ambient", "2/0/105", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Ambient FB", "2/0/106", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Ambient Dimmer", "2/0/107", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Ambient HSV", "2/0/110", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Ambient HSV FB", "2/0/111", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Ambient Hue Dimming", "2/0/112", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 1 Ambient Saturation Dimming", "2/0/113", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Study Primary", "2/0/140", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Study Primary FB", "2/0/141", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Study Primary Dimmer", "2/0/142", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Study Color", "2/0/145", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Study Color FB", "2/0/146", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Study Color Dimmer", "2/0/147", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Study Ambient", "2/0/155", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Study Ambient FB", "2/0/156", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Study Ambient Dimmer", "2/0/157", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Study Ambient HSV", "2/0/160", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Study Ambient HSV FB", "2/0/161", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Study Ambient Hue Dimming", "2/0/162", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Study Ambient Saturation Dimming", "2/0/163", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Primary", "2/0/190", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Primary FB", "2/0/191", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Primary Dimmer", "2/0/192", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Primary Color", "2/0/195", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Primary Color FB", "2/0/196", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Primary Color Dimmer", "2/0/197", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Ambient", "2/0/205", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Ambient FB", "2/0/206", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Ambient Dimmer", "2/0/207", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Ambient HSV", "2/0/210", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Ambient HSV FB", "2/0/211", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Ambient Hue Dimming", "2/0/212", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Bedroom 2 Ambient Saturation Dimming", "2/0/213", "DPT_1"),
C3C.KnxGroupAddress("Dimmer LF Utility", "2/0/225", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Utility FB", "2/0/226", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Utility Dimmer", "2/0/227", "DPT_3"),
C3C.KnxGroupAddress("Dimmer LF Utility Color", "2/0/230", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Utility Color FB", "2/0/231", "DPT_5"),
C3C.KnxGroupAddress("Dimmer LF Utility Color Dimmer", "2/0/232", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Hallway", "2/1/0", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Hallway FB", "2/1/1", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Hallway Dimming", "2/1/2", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Hallway Color", "2/1/5", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Hallway Color FB", "2/1/6", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Hallway Color Dimming", "2/1/7", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Primary", "2/1/15", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Primary FB", "2/1/16", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Primary Dimming", "2/1/17", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Primary Color", "2/1/20", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Primary Color FB", "2/1/21", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Primary Color Dimming", "2/1/22", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Ambient", "2/1/30", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Ambient FB", "2/1/31", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Ambient Dimming", "2/1/32", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Ambient HSV", "2/1/35", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Ambient HSV FB", "2/1/36", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Ambient Hue Dimming", "2/1/37", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Ambient Saturation Dimming", "2/1/38", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Vanity", "2/1/45", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Vanity FB", "2/1/46", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Vanity Dimming", "2/1/47", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Vanity Color", "2/1/50", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Vanity Color FB", "2/1/51", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bathroom Vanity Color Dimming", "2/1/52", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Primary", "2/1/65", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Primary FB", "2/1/66", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Primary Dimming", "2/1/67", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Primary Color", "2/1/70", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Primary Color FB", "2/1/71", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Primary Color Dimming", "2/1/72", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Ambient", "2/1/80", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Ambient FB", "2/1/81", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Ambient Dimming", "2/1/82", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Ambient HSV", "2/1/85", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Ambient HSV FB", "2/1/86", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Ambient Hue Dimming", "2/1/87", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Bedroom Ambient Saturation Dimming", "2/1/88", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Closet", "2/1/95", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Closet FB", "2/1/96", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Closet Dimming", "2/1/97", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Closet Color", "2/1/100", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Closet Color FB", "2/1/101", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Closet Color Dimming", "2/1/102", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Living room Primary", "2/1/105", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Living room Primary FB", "2/1/106", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Living room Primary Dimming", "2/1/107", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Living room Primary Color", "2/1/110", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Living room Primary Color FB", "2/1/111", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Living room Primary Color Dimming", "2/1/112", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Living room Ambient", "2/1/120", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Living room Ambient FB", "2/1/121", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Living room Ambient Dimming", "2/1/122", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Living room Ambient HSV", "2/1/125", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Living room Ambient HSV FB", "2/1/126", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Living room Ambient Hue Dimming", "2/1/127", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Living room Ambient Saturation Dimming", "2/1/128", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Office Primary", "2/1/135", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Office Primary FB", "2/1/136", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Office Primary Dimming", "2/1/137", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Office Color", "2/1/140", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Office Color FB", "2/1/141", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Office Color Dimming", "2/1/142", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Dining room", "2/1/150", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Dining room FB", "2/1/151", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Dining room Dimming", "2/1/152", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Dining Room Color", "2/1/155", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Dining Room Color FB", "2/1/156", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Dining Room Color Dimming", "2/1/157", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Primary", "2/1/165", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Primary FB", "2/1/166", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Primary Dimming", "2/1/167", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Primary Color", "2/1/170", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Primary Color FB", "2/1/171", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Primary Color Dimming", "2/1/172", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Ambient", "2/1/180", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Ambient FB", "2/1/181", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Ambient Dimming", "2/1/182", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Ambient HSV", "2/1/185", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Ambient HSV FB", "2/1/186", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Ambient Hue Dimming", "2/1/187", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Ambient Saturation Dimming", "2/1/188", "DPT_1"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Counter", "2/1/195", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Counter FB", "2/1/196", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Counter Dimming", "2/1/197", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Counter Color", "2/1/200", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Counter Color FB", "2/1/201", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Kitchen Counter Color Dimming", "2/1/202", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Pantry", "2/1/210", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Pantry FB", "2/1/211", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Pantry Dimming", "2/1/212", "DPT_3"),
C3C.KnxGroupAddress("Dimmer UF Pantry Color", "2/1/215", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Pantry Color FB", "2/1/216", "DPT_5"),
C3C.KnxGroupAddress("Dimmer UF Pantry Color Dimming", "2/1/217", "DPT_3"),
C3C.KnxGroupAddress("Dimmer Staircase Tree Dimming", "2/2/0", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Staircase Tree Value", "2/2/1", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Staircase Tree Value Feedback", "2/2/2", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Staircase handrail Swtich", "2/2/20", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Staircase handrail Value", "2/2/21", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Staircase handrail Value Feedback", "2/2/22", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Staircase handrail bottom Dimming", "2/2/35", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Staircase handrail bottom Value", "2/2/36", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Staircase handrail bottom Value Feedback", "2/2/37", "DPT_1"),
C3C.KnxGroupAddress("Dimmer EXT Terrace Dimming", "2/3/0", "DPT_1"),
C3C.KnxGroupAddress("Dimmer EXT Terrace Value", "2/3/1", "DPT_1"),
C3C.KnxGroupAddress("Dimmer EXT Terrace Value Feedback", "2/3/2", "DPT_1"),
C3C.KnxGroupAddress("Dimmer EXT Entrance Value Feedback", "2/3/20", "DPT_1"),
C3C.KnxGroupAddress("Dimmer EXT Entrance Dimming", "2/3/21", "DPT_1"),
C3C.KnxGroupAddress("Dimmer EXT Entrance Value", "2/3/22", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Parking place Dimming", "2/4/0", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Parking place Value", "2/4/1", "DPT_1"),
C3C.KnxGroupAddress("Dimmer Parking place Value Feedback", "2/4/2", "DPT_1"),
C3C.KnxGroupAddress("Heat LF Hallway Temperature FB", "3/0/0", "DPT_9"),
C3C.KnxGroupAddress("Heat LF Bathroom Temperature FB", "3/0/30", "DPT_9"),
C3C.KnxGroupAddress("Heat LF Bathroom Ladder boost", "3/0/40", "DPT_1"),
C3C.KnxGroupAddress("Heat LF Bathroom Ladder boost FB", "3/0/41", "DPT_1"),
C3C.KnxGroupAddress("Heat LF Laundry Temperature FB", "3/0/60", "DPT_1"),
C3C.KnxGroupAddress("Heat LF Bedroom 1 Temperature FB", "3/0/90", "DPT_9"),
C3C.KnxGroupAddress("Heat LF Study Temperature FB", "3/0/120", "DPT_9"),
C3C.KnxGroupAddress("Heat LF Bedroom 2 Temperature FB", "3/0/150", "DPT_9"),
C3C.KnxGroupAddress("Heat LF Technical Room Temperature FB", "3/0/180", "DPT_9"),
C3C.KnxGroupAddress("Heat UF Hallway Temperature FB", "3/1/0", "DPT_9"),
C3C.KnxGroupAddress("Heat UF Bathroom Temperature FB", "3/1/30", "DPT_9"),
C3C.KnxGroupAddress("Heat UF Bathroom Ladder boost", "3/1/40", "DPT_1"),
C3C.KnxGroupAddress("Heat UF Bathroom Ladder boost FB", "3/1/41", "DPT_1"),
C3C.KnxGroupAddress("Heat UF Bedroom Temperature FB", "3/1/60", "DPT_9"),
C3C.KnxGroupAddress("Heat UF Living Room Temperature FB", "3/1/90", "DPT_9"),
C3C.KnxGroupAddress("Heat UF Kitchen Temperature FB", "3/1/120", "DPT_9"),
C3C.KnxGroupAddress("Heat Circulation Pump", "3/5/0", "DPT_1"),
C3C.KnxGroupAddress("Heat Circulation Pump FB", "3/5/1", "DPT_1"),
C3C.KnxGroupAddress("Heat Hot Water Circulation State", "3/6/2", "DPT_1"),
C3C.KnxGroupAddress("Heat Hot Water Circulation Emergency State", "3/6/3", "DPT_1"),
C3C.KnxGroupAddress("Heat Hot Water Circulation Control Value", "3/6/4", "DPT_5"),
C3C.KnxGroupAddress("Heat Heating-Cooling", "3/7/0", "DPT_1"),
C3C.KnxGroupAddress("Heat Heating-Cooling State", "3/7/1", "DPT_1"),
C3C.KnxGroupAddress("Heat Temperature Setpoint", "3/7/2", "DPT_1"),
C3C.KnxGroupAddress("Heat Temperature Setpoint State", "3/7/3", "DPT_1"),
C3C.KnxGroupAddress("Heat Heating Off lock", "3/7/4", "DPT_1"),
C3C.KnxGroupAddress("Heat UF+LF Heating Circulation Pump", "3/7/20", "DPT_1"),
C3C.KnxGroupAddress("Heat UF+LF Heating Circulation Pump State", "3/7/21", "DPT_1"),
C3C.KnxGroupAddress("Vent LF PLACEHOLDER Hallway", "4/0/0", "DPT_1"),
C3C.KnxGroupAddress("Vent LF Hallway Valve IN", "4/0/10", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Hallway Valve IN FB", "4/0/11", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Bathroom CO2 FB", "4/0/30", "DPT_9"),
C3C.KnxGroupAddress("Vent LF Bathroom Humidity FB", "4/0/31", "DPT_9"),
C3C.KnxGroupAddress("Vent LF Bathroom boost", "4/0/35", "DPT_1"),
C3C.KnxGroupAddress("Vent LF Bathroom boost FB", "4/0/36", "DPT_1"),
C3C.KnxGroupAddress("Vent LF Bathroom Valve IN", "4/0/40", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Bathroom Valve IN FB", "4/0/41", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Bathroom Valve OUT", "4/0/42", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Bathroom Valve OUT FB", "4/0/43", "DPT_5"),
C3C.KnxGroupAddress("Vent LF PLACEHOLDER Laundry", "4/0/60", "DPT_1"),
C3C.KnxGroupAddress("Vent LF Bedroom 1 CO2 FB", "4/0/90", "DPT_9"),
C3C.KnxGroupAddress("Vent LF Bedroom 1 Humidity FB", "4/0/91", "DPT_9"),
C3C.KnxGroupAddress("Vent LF Bedroom 1 Valve IN", "4/0/100", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Bedroom 1 Valve IN FB", "4/0/101", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Study CO2 FB", "4/0/120", "DPT_9"),
C3C.KnxGroupAddress("Vent LF Study Humidity FB", "4/0/121", "DPT_9"),
C3C.KnxGroupAddress("Vent LF Study Valve IN", "4/0/130", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Study Valve IN FB", "4/0/131", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Study Valve IN Lock", "4/0/132", "DPT_1"),
C3C.KnxGroupAddress("Vent LF Bedroom 2 CO2 FB", "4/0/150", "DPT_9"),
C3C.KnxGroupAddress("Vent LF Bedroom 2 Humidity FB", "4/0/151", "DPT_9"),
C3C.KnxGroupAddress("Vent LF Bedroom 2 Valve IN", "4/0/160", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Bedroom 2 Valve IN FB", "4/0/161", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Technical Room CO2 FB", "4/0/180", "DPT_1"),
C3C.KnxGroupAddress("Vent LF Technical Room Humidity FB", "4/0/181", "DPT_9"),
C3C.KnxGroupAddress("Vent LF Box Valve OUT", "4/0/240", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Box Valve OUT FB", "4/0/241", "DPT_5"),
C3C.KnxGroupAddress("Vent LF Box Valve OUT Lock", "4/0/242", "DPT_1"),
C3C.KnxGroupAddress("Vent UF PLACEHOLDER Hallway", "4/1/0", "DPT_1"),
C3C.KnxGroupAddress("Vent UF Bathroom CO2 FB", "4/1/30", "DPT_9"),
C3C.KnxGroupAddress("Vent UF Bathroom Humidity FB", "4/1/31", "DPT_9"),
C3C.KnxGroupAddress("Vent UF Bathroom boost", "4/1/35", "DPT_1"),
C3C.KnxGroupAddress("Vent UF Bathroom boost FB", "4/1/36", "DPT_1"),
C3C.KnxGroupAddress("Vent UF Bathroom Valve IN", "4/1/40", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Bathroom Valve IN FB", "4/1/41", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Bathroom Valve IN Lock", "4/1/42", "DPT_1"),
C3C.KnxGroupAddress("Vent UF PLACEHOLDER Bedroom", "4/1/60", "DPT_1"),
C3C.KnxGroupAddress("Vent UF Bedroom Valve IN", "4/1/70", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Bedroom Valve IN FB", "4/1/71", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Bedroom Valve IN Lock", "4/1/72", "DPT_1"),
C3C.KnxGroupAddress("Vent UF Bedroom CO2 FB", "4/1/80", "DPT_9"),
C3C.KnxGroupAddress("Vent UF Bedroom Humidity FB", "4/1/81", "DPT_9"),
C3C.KnxGroupAddress("Vent UF Living Room CO2 FB", "4/1/90", "DPT_9"),
C3C.KnxGroupAddress("Vent UF Living Room Humidity FB", "4/1/91", "DPT_9"),
C3C.KnxGroupAddress("Vent UF Living Room Valve IN", "4/1/100", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Living Room Valve IN FB", "4/1/101", "DPT_5"),
C3C.KnxGroupAddress("Vent UF PLACEHOLDER Office", "4/1/120", "DPT_1"),
C3C.KnxGroupAddress("Vent UF Office Valve IN", "4/1/130", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Office Valve IN FB", "4/1/131", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Bathroom Valve OUT", "4/1/142", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Bathroom Valve OUT FB", "4/1/143", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Bathroom Valve OUT Lock", "4/1/144", "DPT_1"),
C3C.KnxGroupAddress("Vent UF PLACEHOLDER Dining Room", "4/1/150", "DPT_1"),
C3C.KnxGroupAddress("Vent UF PLACEHOLDER Kitchen", "4/1/180", "DPT_1"),
C3C.KnxGroupAddress("Vent UF Kitchen Valve OUT", "4/1/190", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Kitchen Valve OUT FB", "4/1/191", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Kitchen CO2 FB", "4/1/200", "DPT_9"),
C3C.KnxGroupAddress("Vent UF Kitchen Humidity FB", "4/1/201", "DPT_9"),
C3C.KnxGroupAddress("Vent UF Kitchen TVOC FB", "4/1/202", "DPT_9"),
C3C.KnxGroupAddress("Vent UF Kitchen boost", "4/1/205", "DPT_1"),
C3C.KnxGroupAddress("Vent UF Kitchen boost FB", "4/1/206", "DPT_1"),
C3C.KnxGroupAddress("Vent UF Closet+Hallway Valve OUT", "4/1/240", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Closet+Hallway Valve OUT FB", "4/1/241", "DPT_5"),
C3C.KnxGroupAddress("Vent UF Closet+Hallway Valve OUT Lock", "4/1/242", "DPT_1"),
C3C.KnxGroupAddress("Vent Airflow", "4/7/0", "DPT_13"),
C3C.KnxGroupAddress("Vent Standby FB", "4/7/1", "DPT_1"),
C3C.KnxGroupAddress("Vent Temperature: Supply", "4/7/5", "DPT_9"),
C3C.KnxGroupAddress("Vent Temperature: Outdoor", "4/7/6", "DPT_9"),
C3C.KnxGroupAddress("Vent Temperature: Extract", "4/7/7", "DPT_9"),
C3C.KnxGroupAddress("Vent Temperature: Exhaust", "4/7/8", "DPT_9"),
C3C.KnxGroupAddress("Vent Humidity: Supply", "4/7/10", "DPT_9"),
C3C.KnxGroupAddress("Vent Humidity: Outdoor", "4/7/11", "DPT_9"),
C3C.KnxGroupAddress("Vent Humidity: Extract", "4/7/12", "DPT_9"),
C3C.KnxGroupAddress("Vent Humidity: Exhaust", "4/7/13", "DPT_9"),
C3C.KnxGroupAddress("Vent Filter: Remaining (h)", "4/7/25", "DPT_7"),
C3C.KnxGroupAddress("Vent Filter: Replace", "4/7/26", "DPT_1"),
C3C.KnxGroupAddress("Vent Heating-Cooling", "4/7/30", "DPT_1"),
C3C.KnxGroupAddress("Vent Heating-Cooling State", "4/7/31", "DPT_1"),
C3C.KnxGroupAddress("Vent Boost", "4/7/100", "DPT_1"),
C3C.KnxGroupAddress("Vent Boost FB", "4/7/101", "DPT_1"),
C3C.KnxGroupAddress("Vent Auto mode", "4/7/102", "DPT_1"),
C3C.KnxGroupAddress("Vent Auto mode FB", "4/7/103", "DPT_1"),
C3C.KnxGroupAddress("Vent Preset", "4/7/104", "DPT_5"),
C3C.KnxGroupAddress("Vent Preset FB", "4/7/105", "DPT_5"),
C3C.KnxGroupAddress("Vent Preset Away", "4/7/106", "DPT_1"),
C3C.KnxGroupAddress("Vent Preset Away FB", "4/7/107", "DPT_1"),
C3C.KnxGroupAddress("Vent Away function", "4/7/108", "DPT_1"),
C3C.KnxGroupAddress("Vent Away function FB", "4/7/109", "DPT_1"),
C3C.KnxGroupAddress("Vent Temperature profile mode", "4/7/110", "DPT_5"),
C3C.KnxGroupAddress("Vent Temperature profile mode FB", "4/7/111", "DPT_5"),
C3C.KnxGroupAddress("Vent Temperature profile", "4/7/112", "DPT_5"),
C3C.KnxGroupAddress("Vent Temperature profile FB", "4/7/113", "DPT_5"),
C3C.KnxGroupAddress("Vent Boost Time", "4/7/114", "DPT_7"),
C3C.KnxGroupAddress("Vent Boost Time FB", "4/7/115", "DPT_7"),
C3C.KnxGroupAddress("Vent External setpoint", "4/7/116", "DPT_9"),
C3C.KnxGroupAddress("Vent External setpoint FB", "4/7/117", "DPT_9"),
C3C.KnxGroupAddress("Vent Error", "4/7/200", "DPT_1"),
C3C.KnxGroupAddress("Vent Status", "4/7/201", "DPT_5"),
C3C.KnxGroupAddress("Media UF Bathroom Playing", "5/1/100", "DPT_5"),
C3C.KnxGroupAddress("Media UF Bathroom Off", "5/1/101", "DPT_1"),
C3C.KnxGroupAddress("Media UF Bathroom Volume Down", "5/1/103", "DPT_1"),
C3C.KnxGroupAddress("Media UF Bathroom Volume Up", "5/1/104", "DPT_1"),
C3C.KnxGroupAddress("Media UF Bathroom Previous", "5/1/105", "DPT_1"),
C3C.KnxGroupAddress("Media UF Bathroom Next", "5/1/106", "DPT_1"),
C3C.KnxGroupAddress("Media UF Bathroom Preset Cycle Forward", "5/1/107", "DPT_1"),
C3C.KnxGroupAddress("Control LF Hallway Presence", "6/0/0", "DPT_1"),
C3C.KnxGroupAddress("Control LF Hallway Presence Enable", "6/0/1", "DPT_1"),
C3C.KnxGroupAddress("Control LF Hallway Presence Enable Workaround", "6/0/2", "DPT_3"),
C3C.KnxGroupAddress("Control LF Hallway Presence Alarm", "6/0/10", "DPT_1"),
C3C.KnxGroupAddress("Control LF Hallway Presence Alarm State", "6/0/11", "DPT_1"),
C3C.KnxGroupAddress("Control LF Study LED Brightness Night", "6/0/146", "DPT_5"),
C3C.KnxGroupAddress("Control UF Bathroom Presence", "6/1/30", "DPT_1"),
C3C.KnxGroupAddress("Control UF Bathroom Presence Enable", "6/1/31", "DPT_1"),
C3C.KnxGroupAddress("Control UF Bathroom Presence Delayed", "6/1/32", "DPT_1"),
C3C.KnxGroupAddress("Control UF Bathroom Brightness", "6/1/35", "DPT_9"),
}
end

52
src/driver.lua Normal file
View File

@ -0,0 +1,52 @@
local VERSION = "2025.10.0"
local ID_KNX = 1
require("control4-utils.base")
require("control4-utils.hooks")
require("control4-utils.helpers")
require("control4-utils.knx")
C3C.KnxProxy.Setup(ID_KNX)
C3C.RemoteLogger.Setup("c4c-knx-presence")
C3C.Logger.DisableRemoteLogging()
-- C4:AllowExecute(false)
C3C.Lib = {}
require("lib.createContext")
require("lib.state.index")
require("lib.presence.index")
Driver = (function()
local class = {
initialized = false,
online = false,
}
---@param strCommand string
---@param tParams table
function class:Execute(strCommand, tParams)
if strCommand == "ONLINE" then
class.online = true
elseif strCommand == "OFFLINE" then
class.online = false
end
end
function class:SetInitialized()
C3C.RemoteLogger.Info("C3C KNX Presence driver initialized", { version = VERSION })
class.initialized = true
end
return class
end)()
C3C.HookIntoOnDriverLateInit(function()
C3C.OneShotTimer.Add(5000, Driver.SetInitialized, "Initialized")
end)
C3C.HookIntoExecuteCommand(function(strCommand, tParams)
tParams = tParams or {}
strCommand = strCommand or ""
Driver:Execute(strCommand, tParams)
end)

14
src/lib/createContext.lua Normal file
View File

@ -0,0 +1,14 @@
--- @param ga GroupAddress
--- @return table
CreateGroupAddressContext = function(ga)
return {
trace = ga.Name .. "-" .. string.format("%d", C4:GetTime())
}
end
CreateRoomContext = function(location)
return {
location = location,
time = os.clock(),
}
end

View File

@ -0,0 +1,27 @@
(function()
local createContext = function(name)
local ctx = CreateRoomContext("LF Hallway")
ctx.name = name
return ctx
end
C3C.KnxAddresses.Watch("Control LF Hallway Presence", function(ga, state)
local ctx = createContext("GA: " .. ga.Name)
ctx.newVal = state.newVal
C3C.Logger.Debug("Watched Presence", ctx)
if state.newVal == 1 then
time = os.date("*t")
if C3C.Lib.State.DayTime.IsDay() or (time.hour >= 7 and time.hour <= 22) then
C3C.Logger.Debug("Switching on primary light", ctx)
C3C.KnxAddresses.Get("Switch LF Hallway CTRL"):Send(1)
else
C3C.Logger.Debug("Switching on primary light with dimmed control during nighttime", ctx)
C3C.KnxAddresses.Get("Dimmer LF Hallway"):Send(2)
end
else
C3C.Logger.Debug("Presence ended", ctx)
C3C.KnxAddresses.Get("Switch LF Hallway CTRL"):Send(0)
end
end)
end)()

View File

@ -0,0 +1 @@
require("lib.presence.LF.Hallway")

View File

@ -0,0 +1,191 @@
(function()
local disable = false
local present = false
local mediaPlaying = false
local mediaOverridden = false
local lightOverridden = false
C3C.KnxAddresses.Watch("Switch UF Bathroom Primary CTRL FB")
C3C.KnxAddresses.Watch("Switch UF Bathroom Ambient CTRL FB")
local gaPrimaryLightCTRLFB = C3C.KnxAddresses.Get("Switch UF Bathroom Primary CTRL FB")
local gaAmbientLightCTRLFB = C3C.KnxAddresses.Get("Switch UF Bathroom Ambient CTRL FB")
local createContext = function(name)
local ctx = CreateRoomContext("UF Bathroom")
ctx.mediaOverridden = mediaOverridden
ctx.lightOverridden = lightOverridden
ctx.name = name
return ctx
end
local overrideMedia = function(ga)
local ctx = createContext("overrideMedia")
ctx.ga = ga.Name
C3C.Logger.Debug("Overriding media", ctx)
mediaOverridden = true
C3C.OneShotTimer.Add(120 * 1000, function()
ctx.mediaPlaying = mediaPlaying
ctx.present = present
C3C.Logger.Debug("Checking media override reset after 120 seconds", ctx)
if not mediaPlaying and not present then
C3C.Logger.Debug("Resetting media override after 120 seconds", ctx)
mediaOverridden = false
end
end, "checkMediaOverride")
end
local overrideLight = function(ga)
local ctx = createContext("overrideLight")
ctx.ga = ga.Name
C3C.Logger.Debug("Overriding light", ctx)
lightOverridden = true
C3C.OneShotTimer.Add(120 * 1000, function()
ctx.present = present
ctx.gaPrimaryLightCTRLFB = gaPrimaryLightCTRLFB.Value
ctx.gaAmbientLightCTRLFB = gaAmbientLightCTRLFB.Value
C3C.Logger.Debug("Checking light override reset after 120 seconds", ctx)
if not present and gaPrimaryLightCTRLFB.Value ~= 1 and gaAmbientLightCTRLFB.Value ~= 1 then
C3C.Logger.Debug("Resetting light override after 120 seconds", ctx)
lightOverridden = false
end
end, "checkLightOverride")
end
local unOverrideMedia = function()
local ctx = createContext("unOverrideMedia")
C3C.Logger.Debug("Resetting media override", ctx)
mediaOverridden = false
end
local unOverrideLight = function()
local ctx = createContext("unOverrideLight")
C3C.Logger.Debug("Resetting light override", ctx)
lightOverridden = false
end
C3C.KnxAddresses.Watch("Media UF Bathroom Playing", function(ga)
mediaPlaying = ga.Value == 1
end)
C3C.KnxAddresses.Watch("Media UF Bathroom Off", overrideMedia)
C3C.KnxAddresses.Watch("Media UF Bathroom Preset Cycle Forward", overrideMedia)
C3C.KnxAddresses.Watch("Media UF Bathroom Volume Up", overrideMedia)
C3C.KnxAddresses.Watch("Media UF Bathroom Volume Down", overrideMedia)
C3C.KnxAddresses.Watch("Media UF Bathroom Previous", overrideMedia)
C3C.KnxAddresses.Watch("Media UF Bathroom Next", overrideMedia)
C3C.KnxAddresses.Watch("Switch UF Bathroom Primary", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Primary CTRL", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Primary Light 1", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Primary Light 2", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Primary Light Vanity", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Primary Ceiling", overrideLight)
C3C.KnxAddresses.Watch("Dimmer UF Bathroom Primary", overrideLight)
C3C.KnxAddresses.Watch("Dimmer UF Bathroom Primary Dimming", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Ambient", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Ambient CTRL", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Ambient Light 1", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Ambient Light 2", overrideLight)
C3C.KnxAddresses.Watch("Switch UF Bathroom Ambient Toilet", overrideLight)
C3C.KnxAddresses.Watch("Dimmer UF Bathroom Ambient", overrideLight)
C3C.KnxAddresses.Watch("Dimmer UF Bathroom Ambient Dimming", overrideLight)
C3C.KnxAddresses.Watch("UF Bathroom Exit", function()
unOverrideMedia()
unOverrideLight()
end)
local presenceStart = function()
present = true
local ctx = createContext("presenceStart")
C3C.Logger.Debug("Triggered: Presence start", ctx)
if disable then
C3C.Logger.Debug("Presence start disabled", ctx)
return
end
time = os.date("*t")
if C3C.Lib.State.DayTime.IsDay() or (time.hour >= 7 and time.hour <= 19) then
C3C.Logger.Debug("Switching on primary light", ctx)
C3C.KnxAddresses.Get("Switch UF Bathroom Primary CTRL"):Send(1)
elseif time.hour > 19 and time.hour <= 20 then
C3C.Logger.Debug("Switching on primary light with dimmed control during nighttime", ctx)
C3C.KnxAddresses.Get("Dimmer UF Bathroom Primary"):Send(12)
end
C3C.Logger.Debug("Firing event: UpperFloorBathroomMediaStart", ctx)
C4:FireEvent("UpperFloorBathroomMediaStart")
end
local presenceEnd = function()
present = false
local ctx = createContext("presenceEnd")
C3C.Logger.Debug("Triggered: Presence end", ctx)
if not lightOverridden then
if gaPrimaryLightCTRLFB.Value ~ 0 then
C3C.Logger.Debug("Switching off primary light", ctx)
C3C.KnxAddresses.Get("Switch UF Bathroom Primary CTRL"):Send(0)
end
if gaAmbientLightCTRLFB.Value ~= 0 then
C3C.Logger.Debug("Switching off ambient light", ctx)
C3C.KnxAddresses.Get("Switch UF Bathroom Ambient CTRL"):Send(0)
end
end
if not mediaOverridden then
C3C.Logger.Debug("Firing event: UpperFloorBathroomMediaEnd", ctx)
C4:FireEvent("UpperFloorBathroomMediaEnd")
end
unOverrideMedia()
unOverrideLight()
end
local presenceEndDelayed = function()
local ctx = createContext("presenceEndDelayed")
C3C.Logger.Debug("Triggered: Presence end delayed", ctx)
C3C.Logger.Debug("Firing event: UpperFloorBathroomMediaEnd", ctx)
C4:FireEvent("UpperFloorBathroomMediaEnd")
if gaPrimaryLightCTRLFB.Value ~= 0 then
C3C.Logger.Debug("Switching off primary light", ctx)
C3C.KnxAddresses.Get("Switch UF Bathroom Primary CTRL"):Send(0)
end
if gaAmbientLightCTRLFB.Value ~= 0 then
C3C.Logger.Debug("Switching off ambient light", ctx)
C3C.KnxAddresses.Get("Switch UF Bathroom Ambient CTRL"):Send(0)
end
end
C3C.KnxAddresses.Watch("Control UF Bathroom Presence", function(ga, state)
local ctx = createContext("GA: " .. ga.Name)
ctx.newVal = state.newVal
C3C.Logger.Debug("Watched GA Bathroom Presence", ctx)
if state.newVal == 1 then
presenceStart()
else
presenceEnd()
end
end)
C3C.KnxAddresses.Watch("Control UF Bathroom Presence Delayed", function(ga, state)
local ctx = createContext("GA: " .. ga.Name)
ctx.newVal = state.newVal
C3C.Logger.Debug("Watched GA Bathroom Presence Delayed", ctx)
if state.newVal == 1 then
else
presenceEndDelayed()
end
end)
end)()

View File

@ -0,0 +1 @@
require("lib.presence.UF.Bathroom")

View File

@ -0,0 +1,2 @@
require("lib.presence.LF.index")
require("lib.presence.UF.index")

13
src/lib/state/daytime.lua Normal file
View File

@ -0,0 +1,13 @@
(function()
C3C.Lib.State.DayTime = {}
local isDay = false
C3C.KnxAddresses.Watch("Day/Night", function(ga)
isDay = ga.Value == 0
end)
C3C.Lib.State.DayTime.IsDay = function()
return isDay
end
end)()

2
src/lib/state/index.lua Normal file
View File

@ -0,0 +1,2 @@
C3C.Lib.State = {}
require("lib.state.daytime")

View File

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Control4 KNX Ventilation</title>
<meta name="GENERATOR" content="github.com/gomarkdown/markdown markdown processor for Go" />
<meta charset="utf-8" />
</head>
<body>
<h1>Control4 KNX Presence</h1>
<p>Control4 driver managing the presence system</p>
</body>
</html>

BIN
src/www/icons/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
src/www/icons/logo_16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/www/icons/logo_32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

24
tests/test.lua Normal file
View File

@ -0,0 +1,24 @@
-- Include NPM dependencies
dofile('tests/generated.lua')
-- Load test module
require('busted')
-- Load driver
require('driver')
local inspect = require 'inspect'
describe("Driver", function()
it("loads", function()
local start1, result1 = pcall(_G["OnDriverLateInit"])
local start2, result2 = pcall(_G["OnDriverInit"])
if (not start1) then
assert.are.equal(true, start2)
return
end
assert.are.equal(true, start1)
end)
end)