node-red-contrib-knx-ultimate 6.1.1 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -2
- package/examples/KNX AI - Conversational Control with Confirmation.json +374 -0
- package/examples/KNX AI - Telegrambot Direct Chat.json +221 -0
- package/nodes/commonFunctions.js +0 -174
- package/nodes/knxUltimateAI.html +254 -90
- package/nodes/knxUltimateAI.js +1286 -61
- package/nodes/locales/de/knxUltimateAI.html +38 -2
- package/nodes/locales/de/knxUltimateAI.json +16 -3
- package/nodes/locales/en/knxUltimateAI.html +38 -2
- package/nodes/locales/en/knxUltimateAI.json +16 -3
- package/nodes/locales/es/knxUltimateAI.html +38 -2
- package/nodes/locales/es/knxUltimateAI.json +16 -3
- package/nodes/locales/fr/knxUltimateAI.html +38 -2
- package/nodes/locales/fr/knxUltimateAI.json +16 -3
- package/nodes/locales/it/knxUltimateAI.html +38 -2
- package/nodes/locales/it/knxUltimateAI.json +16 -3
- package/nodes/locales/zh-CN/knxUltimateAI.html +38 -2
- package/nodes/locales/zh-CN/knxUltimateAI.json +16 -3
- package/nodes/utils/sysLogger.js +0 -109
- package/package.json +1 -2
- package/resources/KNXAIChatAdapterMappings.js +87 -0
- package/nodes/plugins/knxUltimateMonitor-sidebar-plugin.html +0 -922
package/nodes/commonFunctions.js
CHANGED
|
@@ -7,7 +7,6 @@ const yaml = require('js-yaml')
|
|
|
7
7
|
const dptlib = require('knxultimate').dptlib
|
|
8
8
|
const customHTTP = require('./utils/http')
|
|
9
9
|
const KNXClient = require('knxultimate').KNXClient
|
|
10
|
-
const sysLogger = require('./utils/sysLogger')
|
|
11
10
|
const { normalizeAuthFromAccessTokenQuery } = require('./utils/httpAdminAccessToken')
|
|
12
11
|
|
|
13
12
|
// DATAPONT MANIPULATION HELPERS
|
|
@@ -62,52 +61,6 @@ module.exports = (RED) => {
|
|
|
62
61
|
function commonFunctions () {
|
|
63
62
|
const node = this
|
|
64
63
|
|
|
65
|
-
const ensureBuffer = (rawValue) => {
|
|
66
|
-
if (!rawValue) return null
|
|
67
|
-
if (Buffer.isBuffer(rawValue)) return rawValue
|
|
68
|
-
if (Array.isArray(rawValue)) return Buffer.from(rawValue)
|
|
69
|
-
if (typeof rawValue === 'object' && Array.isArray(rawValue.data)) return Buffer.from(rawValue.data)
|
|
70
|
-
if (rawValue.type === 'Buffer' && Array.isArray(rawValue.data)) return Buffer.from(rawValue.data)
|
|
71
|
-
return null
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const guessDptFromRawValue = (rawBuffer) => {
|
|
75
|
-
if (!rawBuffer || !rawBuffer.length) return null
|
|
76
|
-
if (rawBuffer.length === 1) {
|
|
77
|
-
if (rawBuffer[0] === 0 || rawBuffer[0] === 1) return '1.001'
|
|
78
|
-
return '5.001'
|
|
79
|
-
}
|
|
80
|
-
if (rawBuffer.length === 4) return '14.056'
|
|
81
|
-
if (rawBuffer.length === 2) return '9.001'
|
|
82
|
-
if (rawBuffer.length === 3) return '11.001'
|
|
83
|
-
if (rawBuffer.length === 14) return '16.001'
|
|
84
|
-
|
|
85
|
-
const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy('base')).reduce(toConcattedSubtypes, [])
|
|
86
|
-
for (let index = 0; index < dpts.length; index++) {
|
|
87
|
-
try {
|
|
88
|
-
const resolved = dptlib.resolve(dpts[index].value)
|
|
89
|
-
if (!resolved) continue
|
|
90
|
-
const jsValue = dptlib.fromBuffer(rawBuffer, resolved)
|
|
91
|
-
if (typeof jsValue !== 'undefined') return dpts[index].value
|
|
92
|
-
} catch (error) { /* empty */ }
|
|
93
|
-
}
|
|
94
|
-
return null
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const formatDisplayValue = (value) => {
|
|
98
|
-
if (value === null || value === undefined) return ''
|
|
99
|
-
if (value instanceof Date) return value.toISOString()
|
|
100
|
-
if (typeof value === 'object') {
|
|
101
|
-
try {
|
|
102
|
-
return JSON.stringify(value)
|
|
103
|
-
} catch (error) {
|
|
104
|
-
return String(value)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (typeof value === 'boolean') return value ? 'true' : 'false'
|
|
108
|
-
return String(value)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
64
|
// // Gather infos about all interfaces on the lan and provides a static variable utils.aDiscoveredknxGateways
|
|
112
65
|
// try {
|
|
113
66
|
// require('./utils/utils').DiscoverKNXGateways()
|
|
@@ -624,133 +577,6 @@ module.exports = (RED) => {
|
|
|
624
577
|
}
|
|
625
578
|
})
|
|
626
579
|
|
|
627
|
-
RED.httpAdmin.get('/knxUltimateMonitor', RED.auth.needsPermission('knxUltimate-config.read'), (req, res) => {
|
|
628
|
-
try {
|
|
629
|
-
const server = RED.nodes.getNode(req.query.serverId)
|
|
630
|
-
if (!server) {
|
|
631
|
-
res.json({ items: [], error: 'NO_SERVER' })
|
|
632
|
-
return
|
|
633
|
-
}
|
|
634
|
-
const items = Array.isArray(server.exposedGAs) ? server.exposedGAs.map((entry) => {
|
|
635
|
-
const rawBuffer = ensureBuffer(entry?.rawValue)
|
|
636
|
-
const rawHex = rawBuffer ? rawBuffer.toString('hex') : ''
|
|
637
|
-
let dpt = entry?.dpt
|
|
638
|
-
let guessed = false
|
|
639
|
-
if ((!dpt || dpt === '') && rawBuffer) {
|
|
640
|
-
const inferred = guessDptFromRawValue(rawBuffer)
|
|
641
|
-
if (inferred) {
|
|
642
|
-
dpt = inferred
|
|
643
|
-
guessed = true
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
let value = null
|
|
647
|
-
if (rawBuffer && dpt) {
|
|
648
|
-
try {
|
|
649
|
-
const resolved = dptlib.resolve(dpt)
|
|
650
|
-
if (resolved) value = dptlib.fromBuffer(rawBuffer, resolved)
|
|
651
|
-
} catch (error) { /* empty */ }
|
|
652
|
-
}
|
|
653
|
-
return {
|
|
654
|
-
ga: entry?.ga || '',
|
|
655
|
-
devicename: entry?.devicename || '',
|
|
656
|
-
dpt: dpt || '',
|
|
657
|
-
dptGuessed: guessed,
|
|
658
|
-
rawHex,
|
|
659
|
-
value,
|
|
660
|
-
valueText: formatDisplayValue(value),
|
|
661
|
-
updatedAt: entry?.updatedAt || null
|
|
662
|
-
}
|
|
663
|
-
}).sort((a, b) => a.ga.localeCompare(b.ga)) : []
|
|
664
|
-
res.json({ items })
|
|
665
|
-
} catch (error) {
|
|
666
|
-
try { RED.log.error(`KNXUltimate: knxUltimateMonitor error: ${error.message}`) } catch (e) { }
|
|
667
|
-
res.json({ items: [], error: error.message })
|
|
668
|
-
}
|
|
669
|
-
})
|
|
670
|
-
|
|
671
|
-
RED.httpAdmin.post('/knxUltimateMonitorToggle', RED.auth.needsPermission('knxUltimate-config.write'), (req, res) => {
|
|
672
|
-
try {
|
|
673
|
-
const serverId = req.body?.serverId
|
|
674
|
-
const ga = req.body?.ga
|
|
675
|
-
const server = serverId ? RED.nodes.getNode(serverId) : null
|
|
676
|
-
if (!server) {
|
|
677
|
-
res.json({ status: 'error', error: 'NO_SERVER' })
|
|
678
|
-
return
|
|
679
|
-
}
|
|
680
|
-
if (!ga) {
|
|
681
|
-
res.json({ status: 'error', error: 'NO_GA' })
|
|
682
|
-
return
|
|
683
|
-
}
|
|
684
|
-
const entry = Array.isArray(server.exposedGAs) ? server.exposedGAs.find((item) => item.ga === ga) : undefined
|
|
685
|
-
if (!entry) {
|
|
686
|
-
res.json({ status: 'error', error: 'GA_NOT_FOUND' })
|
|
687
|
-
return
|
|
688
|
-
}
|
|
689
|
-
const rawBuffer = ensureBuffer(entry.rawValue)
|
|
690
|
-
let dpt = entry.dpt
|
|
691
|
-
if (!rawBuffer) {
|
|
692
|
-
res.json({ status: 'error', error: 'NO_CURRENT_VALUE' })
|
|
693
|
-
return
|
|
694
|
-
}
|
|
695
|
-
if (!dpt) {
|
|
696
|
-
const inferred = guessDptFromRawValue(rawBuffer)
|
|
697
|
-
if (inferred) dpt = inferred
|
|
698
|
-
}
|
|
699
|
-
let currentValue = null
|
|
700
|
-
if (dpt) {
|
|
701
|
-
try {
|
|
702
|
-
const resolved = dptlib.resolve(dpt)
|
|
703
|
-
if (resolved) currentValue = dptlib.fromBuffer(rawBuffer, resolved)
|
|
704
|
-
} catch (error) { currentValue = null }
|
|
705
|
-
}
|
|
706
|
-
if (typeof currentValue !== 'boolean') {
|
|
707
|
-
res.json({ status: 'error', error: 'NOT_BOOLEAN' })
|
|
708
|
-
return
|
|
709
|
-
}
|
|
710
|
-
const nextValue = !currentValue
|
|
711
|
-
const sendDpt = dpt || '1.001'
|
|
712
|
-
try {
|
|
713
|
-
server.sendKNXTelegramToKNXEngine({
|
|
714
|
-
grpaddr: ga,
|
|
715
|
-
payload: nextValue,
|
|
716
|
-
dpt: sendDpt,
|
|
717
|
-
outputtype: 'write',
|
|
718
|
-
nodecallerid: 'knxUltimateMonitor'
|
|
719
|
-
})
|
|
720
|
-
} catch (error) {
|
|
721
|
-
res.json({ status: 'error', error: error.message })
|
|
722
|
-
return
|
|
723
|
-
}
|
|
724
|
-
res.json({ status: 'ok', value: nextValue })
|
|
725
|
-
} catch (error) {
|
|
726
|
-
try { RED.log.error(`KNXUltimate: knxUltimateMonitorToggle error: ${error.message}`) } catch (e) { }
|
|
727
|
-
res.json({ status: 'error', error: error.message })
|
|
728
|
-
}
|
|
729
|
-
})
|
|
730
|
-
|
|
731
|
-
RED.httpAdmin.get('/knxUltimateDebugLog', RED.auth.needsPermission('knxUltimate-config.read'), (req, res) => {
|
|
732
|
-
try {
|
|
733
|
-
const rawSince = req.query?.sinceSeq ?? req.query?.since ?? req.query?.after ?? null
|
|
734
|
-
let sinceSeq = null
|
|
735
|
-
if (rawSince !== null && rawSince !== undefined) {
|
|
736
|
-
const parsed = Number(rawSince)
|
|
737
|
-
if (!Number.isNaN(parsed) && Number.isFinite(parsed)) {
|
|
738
|
-
sinceSeq = Math.floor(parsed)
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
const snapshot = sinceSeq === null ? sysLogger.getDebugSnapshot() : sysLogger.getDebugSnapshot({ sinceSeq })
|
|
742
|
-
res.json({
|
|
743
|
-
entries: snapshot.entries,
|
|
744
|
-
latestSeq: snapshot.latestSeq,
|
|
745
|
-
total: snapshot.total,
|
|
746
|
-
limit: snapshot.limit
|
|
747
|
-
})
|
|
748
|
-
} catch (error) {
|
|
749
|
-
try { RED.log.error(`KNXUltimate: knxUltimateDebugLog error: ${error.message}`) } catch (e) { }
|
|
750
|
-
res.json({ entries: [], error: error.message })
|
|
751
|
-
}
|
|
752
|
-
})
|
|
753
|
-
|
|
754
580
|
RED.httpAdmin.post('/KNXUltimateLocateHueDevice', async (req, res) => {
|
|
755
581
|
const respondError = (status, message) => {
|
|
756
582
|
res.status(status).json({ error: message })
|