refactor!: Rename "devices" to "hosts" in "exportHistory" - operation. Prepare extraction of device specific types and alignment with integration layer

This commit is contained in:
Andreas Hilbig 2026-01-06 12:42:43 +01:00
parent 92ffe71684
commit 47640ff13e
10 changed files with 11888 additions and 35 deletions

View file

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="index.ts" type="NodeJSConfigurationType" path-to-node="wsl://Ubuntu@/home/ahilbig/.nvm/versions/node/v22.14.0/bin/node" nameIsGenerated="true" path-to-js-file="src/index.ts" typescript-loader="bundled" working-dir="$PROJECT_DIR$">
<envs>
<env name="ADDITIONAL_RESOLVERS" value="SinglePanelDevice,FourPanelDevice" />
<env name="ADDITIONAL_SCHEMAS" value="./extensions/display_devices.graphql" />
<env name="ADDITIONAL_RESOLVERS" value="SinglePanelDevice,FourPanelDevice,DistanceTracker" />
<env name="ADDITIONAL_SCHEMAS" value="./extensions/display_devices.graphql,./extensions/location_tracker_devices.graphql" />
<env name="DEBUG" value="device-control-center-api:*" />
<env name="ZABBIX_AUTH_TOKEN" value="$ZABBIX_AUTH_TOKEN_VCR_DEV$" />
<env name="ZABBIX_BASE_URL" value="http://cockpit.vcr.develop.hilbigit.com/" />

View file

@ -0,0 +1,49 @@
"""
Represents a message containing information about a specific device and its associated data value.
The class is designed to be extended by other classes that define more structured or specialized types
of device value messages.
"""
interface DeviceValueMessage {
"""
A unique identifier used to distinguish a specific device within the system.
This field is commonly used to associate messages, configurations, or data values
with a particular device.
"""
deviceKey: String
"""
Represents the timestamp at which a specific event, message, or data point was created or recorded.
The format should align with standard expectations (e.g., ISO 8601).
"""
timestamp: String
"""
Represents the name assigned to a set of values that are submitted together with a single timestamp.
This name is associated with a well-defined data structure.
"""
attributeName: String
"""
Represents the name of the sub-topic to which the attribute is submitted.
Classification or grouping of data within a broader topic structure.
"""
topicName: String
"""
Specifies the type or category of the device. Used to define the classification
of a device in the system (capabilities, functionalities, or purpose).
"""
deviceType: String
"""
Retrieves the value associated with the current instance of the object.
"""
value: DeviceValue
}
"""
Marker-interface for device-related data values.
"""
interface DeviceValue {
_empty: String
}

View file

@ -0,0 +1,60 @@
"""
Concrete implementation of a DeviceValueMessage for sensor distance data.
"""
type SensorDistanceMessage implements DeviceValueMessage {
deviceKey: String
timestamp: String
attributeName: String
topicName: String
deviceType: String
value: SensorDistanceValue
}
"""
Represents the payload for a sensor distance measurement.
"""
type SensorDistanceValue implements DeviceValue {
"""
Represents the name of the device that reports or provides distance sensor data.
Uniquely identifies the device within the context of the SensorDistanceValue.
"""
deviceName: String
"""
Represents the MAC address of the device. Typically formatted as a 12-character
hexadecimal string (e.g., "00:1A:2B:3C:4D:5E").
"""
mac: String
"""
Represents the measured or calculated distance value, typically in meters.
Should be non-negative.
"""
distance: Float
"""
Represents the time at which the sensor measurement was recorded.
"""
time: String
_empty: String
}
"""
Represents a coordinate in 3D space with x, y, and z components.
"""
type Position {
x: Float
y: Float
z: Float
}
"""
Represents the result of a position calculation, including the calculated position and accuracy.
"""
type PositionCalculatorResult {
position: Position
accuracy: Float
}

View file

@ -0,0 +1,68 @@
"""
DistanceTracker represents a device which can detect other devices around itself and estimate
the distances, e.g. by using Bluetooth scanning technology and estimating the distance by .
Optionally the
"""
type DistanceTrackerDevice implements Host & Device {
hostid: ID!
"""
Per convention a uuid is used as hostname to identify devices if they do not have a unique hostname
"""
host: String!
deviceType: String
hostgroups: [HostGroup!]
name: String
tags: JSONObject
state: DistanceTrackerState
}
type DistanceTrackerState implements DeviceState {
operational: OperationalDeviceData
current: DistanceTrackerCurrentState
}
type DistanceTrackerCurrentState {
values: DistanceTrackerValues
}
type DistanceTrackerValues {
"""
Aggregated information of devices detected around the tracker
"""
countValues: DeviceCountValues
"""
Information about devices detected nearby
"""
distanceValues: String
}
type DeviceCountValues {
"""
Number of unique deviceKeys detected between timeFrom and timeUnti
"""
count: Int
"""
Start of time interval for the delivered device counting value
"""
timeFrom: Time
"""
End of time interval for the delivered device counting value
"""
timeUntil: Time
}
type DeviceDistanceValues {
"""
Number of unique deviceKeys detected between timeFrom and timeUnti
"""
count: Int
"""
Start of time interval for the delivered device counting value
"""
timeFrom: Time
"""
End of time interval for the delivered device counting value
"""
timeUntil: Time
}

10529
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,7 @@ type Query {
"""
Get all host groups.
If with_hosts==true only groups with attached devices are delivered.
If with_hosts==true only groups with attached hosts are delivered.
Authentication: By zbx_session - cookie or zabbix-auth-token - header
"""
@ -54,19 +54,19 @@ type Query {
locations(name_pattern: String = "", distinct_by_name: Boolean = true, templateids:[String] = null): [Location]
"""
Export device value history from Zabbix
Export history from Zabbix items
Authentication: By zbx_session - cookie or zabbix-auth-token - header
"""
exportDeviceValueHistory(
"(Optional) list of deviceKeys to be included in the result"
deviceKey_filter: [String!],
"(Optional) list of attribute names to be included in the result"
attribute_filter: [String!],
exportHostValueHistory(
"(Optional) list of hostnames to be included in the result"
host_filter: [String!],
"(Optional) list of item keys to be included in the result"
itemKey_filter: [String!],
"""
(Optional) timestamp of earliest deviceValue"""
(Optional) timestamp of earliest value"""
time_from: DateTime,
"""(Optional) timestamp of last deviceValue """
"""(Optional) timestamp of last value """
time_until: DateTime,
"""Results are sorted by timestamps - ascending or descending order may be specified
using this parameter"""
@ -83,7 +83,7 @@ type Query {
"""
type: StorageItemType = FLOAT
):DeviceValueExportResponse
):HistoryExportResponse
"""
Return all user permissions. If objectNames is provided return only the permissions related to the objects within
@ -234,7 +234,7 @@ type UserPermission {
objectName: String!
}
########################################################
# Device values
# Values
########################################################
enum StorageItemType {
@ -243,7 +243,7 @@ enum StorageItemType {
TEXT
}
type DeviceValueExportResponse {
type HistoryExportResponse {
result: [JSONObject!]
error: ApiError
}
@ -270,15 +270,14 @@ type Mutation {
"""
(Mass) Import edge devices and assign them to host groups by groupid or groupName.
(Mass) Import hosts and assign them to host groups by groupid or groupName.
Return value: If no error occurs a hostid will be returned for each created device,
otherwise the return object will contain an error message. The hostid will be equal
to the provided deviceKey if the operation was successfull.
Return value: If no error occurs a hostid will be returned for each created host,
otherwise the return object will contain an error message.
Authentication: By zbx_session - cookie or zabbix-auth-token - header
"""
importHosts(devices: [CreateHost!]!):[CreateHostResponse!]
importHosts(hosts: [CreateHost!]!):[CreateHostResponse!]
importUserRights(input: UserRightsInput!, dryRun: Boolean! = true): ImportUserRightsResult
}

View file

@ -8,12 +8,11 @@ import {
Permission,
QueryAllHostsArgs,
QueryAllHostGroupsArgs,
QueryExportDeviceValueHistoryArgs,
QueryExportUserRightsArgs,
QueryHasPermissionsArgs,
QueryUserPermissionsArgs,
Resolvers,
StorageItemType, Host,
StorageItemType, Host, QueryExportHostValueHistoryArgs,
} from "../generated/graphql.js";
import {HostImporter} from "../execution/host_importer";
@ -92,11 +91,11 @@ export function createResolvers(): Resolvers {
)
},
exportDeviceValueHistory: (_parent: any, args: QueryExportDeviceValueHistoryArgs, {
exportHostValueHistory: (_parent: any, args: QueryExportHostValueHistoryArgs, {
zabbixAuthToken,
cookie
}: any) => {
return HostValueExporter.exportDeviceData(args, zabbixAuthToken, cookie)
return HostValueExporter.exportHistory(args, zabbixAuthToken, cookie)
},
exportUserRights: async (_, args: QueryExportUserRightsArgs, {
@ -134,7 +133,7 @@ export function createResolvers(): Resolvers {
zabbixAuthToken,
cookie
}: any) => {
return HostImporter.importHosts(args.devices, zabbixAuthToken, cookie)
return HostImporter.importHosts(args.hosts, zabbixAuthToken, cookie)
},
importUserRights: async (_, args: MutationImportUserRightsArgs, {
zabbixAuthToken,

View file

@ -1,7 +1,6 @@
import {
ApiError,
DeviceValueExportResponse,
QueryExportDeviceValueHistoryArgs,
HistoryExportResponse, QueryExportHostValueHistoryArgs,
StorageItemType
} from "../generated/graphql.js";
import {ApiErrorCode, ApiErrorMessage} from "../model/model_enum_values.js";
@ -21,7 +20,7 @@ type ItemMapResponse = {
}
export class HostValueExporter {
static async exportDeviceData(args: QueryExportDeviceValueHistoryArgs, zabbixAuthToken?: string, cookie?: string): Promise<DeviceValueExportResponse> {
static async exportHistory(args: QueryExportHostValueHistoryArgs, zabbixAuthToken?: string, cookie?: string): Promise<HistoryExportResponse> {
let itemMapResponse: ItemMapResponse = await HostValueExporter.queryItemsForFilterArgs(args, zabbixAuthToken, cookie);
if (itemMapResponse.error || !itemMapResponse.items) {
return {
@ -74,16 +73,16 @@ export class HostValueExporter {
}
}
static async queryItemsForFilterArgs(args: QueryExportDeviceValueHistoryArgs, zabbixAuthToken?: string, cookie?: string): Promise<ItemMapResponse> {
let deviceKeys = args.deviceKey_filter
let attributeNames = args.attribute_filter
static async queryItemsForFilterArgs(args: QueryExportHostValueHistoryArgs, zabbixAuthToken?: string, cookie?: string): Promise<ItemMapResponse> {
let hostFilter = args.host_filter
let itemKeyFilter = args.itemKey_filter
let items: QueryZabbixItemResponse[] | ZabbixErrorResult = await new ZabbixQueryItemsRequest(zabbixAuthToken, cookie)
.executeRequestReturnError(zabbixAPI, new ParsedArgs(
{
filter: {
host: deviceKeys,
key_: attributeNames
host: hostFilter,
key_: itemKeyFilter
},
tags: [{"tag": "hasValue", "operator": 1, "value": "true"}]
}))

View file

@ -85,12 +85,12 @@ export class HostImporter {
return result
}
static async importHosts(devices: InputMaybe<Array<CreateHost>> | undefined, zabbixAuthToken?: string, cookie?: string) {
if (!devices) {
static async importHosts(hosts: InputMaybe<Array<CreateHost>> | undefined, zabbixAuthToken?: string, cookie?: string) {
if (!hosts) {
return null
}
let result: CreateHostResponse[] = []
for (let device of devices) {
for (let device of hosts) {
let groupids = device.groupids
if (!groupids) {
groupids = await GroupHelper.findHostGroupIdsByName([ZABBIX_EDGE_DEVICE_BASE_GROUP, ...device.groupNames], zabbixAPI, zabbixAuthToken, cookie)

1150
src/generated/graphql.ts Normal file

File diff suppressed because it is too large Load diff