iobroker.javascript
Version:
Rules Engine for ioBroker
1,192 lines (1,054 loc) • 141 kB
TypeScript
// import all modules that are available in the sandbox
// this has a nice side effect that we may augment the global scope
import type * as os from 'node:os';
import type { ChildProcess, ExecException } from 'node:child_process';
export interface FsStats {
isFile(): boolean;
isDirectory(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
dev: number;
ino: number;
mode: number;
nlink: number;
uid: number;
gid: number;
rdev: number;
size: number;
blksize: number;
blocks: number;
atimeMs: number;
mtimeMs: number;
ctimeMs: number;
birthtimeMs: number;
atime: Date;
mtime: Date;
ctime: Date;
birthtime: Date;
}
declare const __brand: unique symbol;
type Brand<B> = { [__brand]: B };
export type Branded<T, B> = T & Brand<B>;
type SubscribeObject = {
name: string;
pattern: string;
callback: (id: string, obj?: iobJS.Object | null) => void;
};
type EmptyCallback = () => void | Promise<void>;
type ErrorCallback = (err?: Error) => void | Promise<void>;
type GenericCallback<T> = (err?: Error | null, result?: T) => void | Promise<void>;
type SimpleCallback<T> = (result?: T) => void | Promise<void>;
type MessageCallback<T> = (data: T, callback: iobJS.MessageCallback) => void | Promise<void>;
type SecondParameterOf<T extends (...args: any[]) => any> = T extends (arg0: any, arg1: infer R, ...args: any[]) => any
? R
: never;
/** Infers the return type from a callback-style API and strips out null and undefined */
type NonNullCallbackReturnTypeOf<T extends (...args: any[]) => any> = Exclude<SecondParameterOf<T>, null | undefined>;
/** Infers the return type from a callback-style API and leaves null and undefined in */
type CallbackReturnTypeOf<T extends (...args: any[]) => any> = SecondParameterOf<T>;
/** Returns a type that requires at least one of the properties from the given type */
type AtLeastOne<T, U = { [K in keyof T]-?: T[K] }> = { [K in keyof U]: { [P in K]: U[P] } }[keyof U];
/** Returns all possible keys of a union of objects */
type AllKeys<T> = T extends any ? keyof T : never;
/** Simplifies mapped types to their basic forms */
type Simplify<U> = U extends infer O ? { [K in keyof O]: O[K] } : never;
/** Takes an object type and adds all missing properties from the Keys union with the type `never` */
type AddMissingNever<T, Keys extends string | number | symbol> = {
[K in Keys]: K extends keyof T ? T[K] : never;
};
/**
* Takes a union of objects and returns an object type
* which has all properties that exist on at least one of the objects.
*
* E.g. CombineObjectUnion<{a: 1} | {b: 2}> = {a: 1; b: 2};
*/
type CombineObjectUnion<
T,
Keys extends string | number | symbol = AllKeys<T>,
O = T extends any ? AddMissingNever<T, Keys> : never,
> = Simplify<{ [K in Keys]: K extends keyof O ? O[K] : never }>;
/**
* Takes a union of ioBroker Object types and returns a combined object type
* which has all properties that could exist on at least one of the objects.
*
* Note: This is not entirely sound to work with, but better for JS and working with read objects
*/
type AnyOf<
T,
Keys extends string | number | symbol = AllKeys<T>,
O = T extends any ? AddMissingNever<T, Keys> : never,
> = Simplify<{
[K in Keys]: K extends keyof O
? O[K] extends any[]
? O[K]
: O[K] extends Record<any, any>
? CombineObjectUnion<O[K]>
: O[K]
: never;
}>;
// tslint:disable:no-namespace
declare global {
namespace iobJS {
/** Two-way mapping for state quality ("q" attribute of a state) */
interface STATE_QUALITY {
/** The default value for a state */
GOOD: 0x00;
/** General problem */
BAD: 0x01;
/** The instance cannot establish a connection */
CONNECTION_PROBLEM: 0x02;
/** Substitute value from controller. Do not set this in adapters */
SUBSTITUTE_FROM_CONTROLLER: 0x10;
/** Quality for default values */
SUBSTITUTE_INITIAL_VALUE: 0x20;
/** Substitute value from instance or device */
SUBSTITUTE_DEVICE_INSTANCE_VALUE: 0x40;
/** Substitute value from a sensor */
SUBSTITUTE_SENSOR_VALUE: 0x80;
/** General problem by instance */
GENERAL_INSTANCE_PROBLEM: 0x11;
/** General problem by device */
GENERAL_DEVICE_PROBLEM: 0x41;
/** General problem by sensor */
GENERAL_SENSOR_PROBLEM: 0x81;
/** The instance is not connected */
INSTANCE_NOT_CONNECTED: 0x12;
/** The device is not connected */
DEVICE_NOT_CONNECTED: 0x42;
/** The sensor is not connected */
SENSOR_NOT_CONNECTED: 0x82;
/** The device has reported an error */
DEVICE_ERROR_REPORT: 0x44;
/** The sensor has reported an error */
SENSOR_ERROR_REPORT: 0x84;
}
type StateValue = string | number | boolean | null;
interface State {
/** The value of the state. */
val: StateValue;
/** Direction flag: false for desired value and true for actual value. Default: false. */
ack: boolean;
/** Unix timestamp. Default: current time */
ts: number;
/** Unix timestamp of the last time the value changed */
lc: number;
/** Name of the adapter instance which set the value, e.g. "system.adapter.web.0" */
from: string;
/** The user who set this value */
user?: string;
/** Optional time in seconds after which the state is reset to null */
expire?: number;
/** Optional quality of the state value */
q?: STATE_QUALITY[keyof STATE_QUALITY];
/** Optional comment */
c?: string;
}
type SettableState = AtLeastOne<State>;
interface IdObject {
device?: string;
channel?: string;
state?: string;
}
type Session = any; // TODO: implement
/** Defines access rights for a single object type */
interface ObjectOperationPermissions {
/** Whether a user may enumerate objects of this type */
list: boolean;
/** Whether a user may read objects of this type */
read: boolean;
/** Whether a user may write objects of this type */
write: boolean;
/** Whether a user may create objects of this type */
create: boolean;
/** Whether a user may delete objects of this type */
delete: boolean;
}
/** Defines the rights a user or group has to change objects */
interface ObjectPermissions {
/** The access rights for files */
file: ObjectOperationPermissions;
/** The access rights for objects */
object: ObjectOperationPermissions;
/** The access rights for users/groups */
users: ObjectOperationPermissions;
/** The access rights for states */
state?: ObjectOperationPermissions;
}
/** Defined the complete set of access rights a user has */
interface PermissionSet extends ObjectPermissions {
/** The name of the user this ACL is for */
user: string;
/** The name of the groups this ACL was merged from */
groups: string[];
/** The access rights for certain commands */
other: {
execute: boolean;
http: boolean;
sendto: boolean;
};
}
interface Permission {
/** The type of the permission */
type: string;
/** Defines which kind of operation is required */
operation: string;
}
interface ObjectOrStatePermission extends Permission {
type: 'object' | 'file' | 'users' | 'state';
operation: 'list' | 'read' | 'write' | 'create' | 'delete';
}
interface OtherPermission extends Permission {
type: 'other';
operation: 'execute' | 'http' | 'sendto';
}
interface CommandsPermissions {
// TODO: Are all properties required or is a partial object ok?
getObject: ObjectOrStatePermission;
getObjects: ObjectOrStatePermission;
getObjectView: ObjectOrStatePermission;
setObject: ObjectOrStatePermission;
subscribeObjects: ObjectOrStatePermission;
unsubscribeObjects: ObjectOrStatePermission;
getStates: ObjectOrStatePermission;
getState: ObjectOrStatePermission;
setState: ObjectOrStatePermission;
getStateHistory: ObjectOrStatePermission;
subscribe: ObjectOrStatePermission;
unsubscribe: ObjectOrStatePermission;
getVersion: Permission;
httpGet: OtherPermission;
sendTo: OtherPermission;
sendToHost: OtherPermission;
readFile: ObjectOrStatePermission;
readFile64: ObjectOrStatePermission;
writeFile: ObjectOrStatePermission;
writeFile64: ObjectOrStatePermission;
unlink: ObjectOrStatePermission;
rename: ObjectOrStatePermission;
mkdir: ObjectOrStatePermission;
readDir: ObjectOrStatePermission;
chmodFile: ObjectOrStatePermission;
authEnabled: Permission;
disconnect: Permission;
listPermissions: Permission;
getUserPermissions: ObjectOrStatePermission;
}
type UserGroup = any; // TODO find out how this looks like
// interface UserGroup { }
/** Contains information about a user */
interface User {
/** Which groups this user belongs to */
groups: UserGroup[];
/** Access rights of this user */
acl: ObjectPermissions;
}
/** Parameters for adapter.getObjectView */
interface GetObjectViewParams {
/** First id to include in the return list */
startkey?: string;
/** Last id to include in the return list */
endkey?: string;
/** Whether docs should be included in the return list */ // TODO: What are docs?
include_docs?: boolean;
}
/** Parameters for adapter.getObjectList */
type GetObjectListParams = GetObjectViewParams;
interface Logger {
/** log a message with silly level */
silly(message: string): void;
/** log a message with debug level */
debug(message: string): void;
/** log a message with info level (default output level for all adapters) */
info(message: string): void;
/** log a message with warning severity */
warn(message: string): void;
/** log a message with error severity */
error(message: string): void;
/** Verbosity of the log output */
level: LogLevel;
}
/** Log message */
interface LogMessage {
/** unique ID */
_id: number;
/** id of the source instance */
from: string;
/** log level */
severity: string;
/** timestamp */
ts: number;
/** actual content */
message: string;
}
interface Certificates {
/** private key file */
key: string;
/** public certificate */
cert: string;
/** chained CA certificates */
ca?: string;
}
type MessagePayload = any;
/** Callback information for a passed message */
interface MessageCallbackInfo {
/** The original message payload */
message: MessagePayload;
/** ID of this callback */
id: number;
/** If ack is false, it means the message is a request. If ack is true, it means the message is a response */
ack: boolean;
/** Timestamp of this message */
time: number;
}
interface SendableMessage {
/** The command to be executed */
command: string;
/** The message payload */
message: MessagePayload;
/** The source of this message */
from: string;
/** Callback information. This is set when the source expects a response */
callback?: MessageCallbackInfo;
}
/** A message being passed between adapter instances */
interface Message extends SendableMessage {
/** ID of this message */
_id: number;
}
type Log = any; // TODO: define this https://github.com/ioBroker/ioBroker.js-controller/blob/master/lib/states/statesInMemServer.js#L873
type EnumList = string | string[];
type Plugin = Record<string, any>; // TODO: Add definition
interface DirectoryEntry {
file: string;
stats: FsStats;
isDir: boolean;
acl: any; // access control list object
modifiedAt: number;
createdAt: number;
}
interface GetHistoryOptions {
instance?: string;
/** Start time in ms */
start?: number;
/** End time in ms. If not defined, it is "now" */
end?: number;
/** Step in ms of intervals. Used in aggregate (max, min, average, total, ...) */
step?: number;
/** number of values if aggregate is 'onchange' or number of intervals if other aggregate method. Count will be ignored if step is set, else default is 500 if not set */
count?: number;
/** if `from` field should be included in answer */
from?: boolean;
/** if `ack` field should be included in answer */
ack?: boolean;
/** if `q` field should be included in answer */
q?: boolean;
/** if `id` field should be included in answer */
addId?: boolean;
/** do not return more entries than limit */
limit?: number;
/** round result to number of digits after decimal point */
round?: number;
/** if null values should be included (false), replaced by last not null value (true) or replaced with 0 (0) */
ignoreNull?: boolean | 0;
/** This number will be returned in answer, so the client can assign the request for it */
sessionId?: number;
/** aggregate method (Default: 'average') */
aggregate?:
| 'onchange'
| 'minmax'
| 'min'
| 'max'
| 'average'
| 'total'
| 'count'
| 'none'
| 'percentile'
| 'quantile'
| 'integral'
| 'integralTotal';
/** Returned data is normally sorted ascending by date, this option lets you return the newest instead of the oldest values if the number of returned points is limited */
returnNewestEntries?: boolean;
/** By default, the additional border values are returned to optimize charting. Set this option to true if this is not wanted (e.g., for script data processing) */
removeBorderValues?: boolean;
/** when using aggregate method `percentile` defines the percentile level (0..100)(defaults to 50) */
percentile?: number;
/** when using aggregate method `quantile` defines the quantile level (0..1)(defaults to 0.5) */
quantile?: number;
/** when using aggregate method `integral` defines the unit in seconds (defaults to 60 seconds). E.g., to get integral in hours for Wh or such, set to 3600. */
integralUnit?: number;
/** when using aggregate method `integral` defines the interpolation method (defaults to `none`). */
integralInterpolation?: 'none' | 'linear';
/** If user is set, it will be checked if this user may read the variable */
user?: `system.user.${string}`;
}
interface DelObjectOptions {
/** Whether all child objects should be deleted as well */
recursive?: boolean;
// Allow non-documented properties
[other: string]: unknown;
}
interface ExtendObjectOptionsPreserve {
[prop: string]: ExtendObjectOptionsPreserve | boolean | string[];
}
interface ExtendObjectOptions {
/** Which properties of the original object should be preserved */
preserve?: ExtendObjectOptionsPreserve;
// Allow non-documented properties
[other: string]: unknown;
}
/** Predefined notification scopes and their categories */
interface NotificationScopes {
system:
| 'memIssues'
| 'fsIoErrors'
| 'noDiskSpace'
| 'accessErrors'
| 'nonExistingFileErrors'
| 'remoteHostErrors'
| 'restartLoop'
| 'fileToJsonl';
[other: string]: string;
}
/** Additional context for the notification which can be used by notification processing adapters */
interface NotificationContextData {
/** Use a `key` specific to the adapter or if a feature is supported by all adapters of a type, the type (e.g. `messaging`) is also fine. */
[adapterNameOrAdapterType: string]: unknown;
}
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface AdapterConfig {
// This is a stub to be augmented in every adapter
}
type ReadyHandler = () => void | Promise<void>;
type ObjectChangeHandler = (id: string, obj: iobJS.Object | null | undefined) => void | Promise<void>;
type OriginalStateChangeHandler = (id: string, obj: State | null | undefined) => void | Promise<void>;
type OriginalFileChangeHandler = (id: string, fileName: string, size: number | null) => void;
type MessageHandler = (obj: Message) => void | Promise<void>;
type UnloadHandler = (callback: EmptyCallback) => void | Promise<void>;
type ErrorHandler = (err: Error) => boolean;
type EmptyCallback = () => void;
type ErrorCallback = (err?: Error | null) => void;
/** Special variant of ErrorCallback for methods where Node.js returns an ErrnoException */
type ErrnoCallback = (err?: NodeJS.ErrnoException | null) => void;
// TODO: Redefine callbacks as subclass of GenericCallback
type GenericCallback<T> = (err?: Error | null, result?: T) => void;
/** Due to backward compatibility first param can be result or error */
type OriginalMessageCallback = (response?: Message | Error) => void;
type OriginalSetObjectCallback = (err?: Error | null, obj?: { id: string }) => void;
type OriginalSetObjectPromise = Promise<NonNullCallbackReturnTypeOf<OriginalSetObjectCallback>>;
type GetEnumCallback = (err?: Error | null, enums?: Record<string, EnumObject>, requestedEnum?: string) => void;
type GetEnumsCallback = (
err?: Error | null,
result?: {
[groupName: string]: Record<string, EnumObject>;
},
) => void;
type GetEnumsPromise = Promise<NonNullCallbackReturnTypeOf<GetEnumsCallback>>;
type GetObjectsCallback = (err?: Error | null, objects?: Record<string, iobJS.Object>) => void;
type GetObjectsPromise = Promise<NonNullCallbackReturnTypeOf<GetObjectsCallback>>;
type GetObjectsCallbackTyped<T extends ObjectType> = (
err?: Error | null,
objects?: Record<string, iobJS.AnyObject & { type: T }>,
) => void;
type GetObjectsPromiseTyped<T extends ObjectType> = Promise<
NonNullCallbackReturnTypeOf<GetObjectsCallbackTyped<T>>
>;
type FindObjectCallback = (
/** If an error happened, this contains the message */
err?: Error | null,
/** If an object was found, this contains the ID */
id?: string,
/** If an object was found, this contains the common.name */
name?: StringOrTranslated,
) => void;
// This is a version used by GetDevices/GetChannelsOf/GetStatesOf
type GetObjectsCallback3<T extends BaseObject> = (err?: Error | null, result?: T[]) => void;
type SecondParameterOf<T extends (...args: any[]) => any> = T extends (
arg0: any,
arg1: infer R,
...args: any[]
) => any
? R
: never;
/** Infers the return type from a callback-style API and strips out null and undefined */
type NonNullCallbackReturnTypeOf<T extends (...args: any[]) => any> = Exclude<
SecondParameterOf<T>,
null | undefined
>;
/** Infers the return type from a callback-style API and leaves null and undefined in */
type CallbackReturnTypeOf<T extends (...args: any[]) => any> = SecondParameterOf<T>;
type OriginalGetStateCallback = (err?: Error | null, state?: State | null) => void;
type GetStatePromise = Promise<CallbackReturnTypeOf<OriginalGetStateCallback>>;
type GetStatesCallback = (err?: Error | null, states?: Record<string, State>) => void;
type GetStatesPromise = Promise<NonNullCallbackReturnTypeOf<GetStatesCallback>>;
type SetStateCallback = (err?: Error | null, id?: string) => void;
type SetStatePromise = Promise<NonNullCallbackReturnTypeOf<SetStateCallback>>;
type SetStateChangedCallback = (err?: Error | null, id?: string, notChanged?: boolean) => void;
type SetStateChangedPromise = Promise<NonNullCallbackReturnTypeOf<SetStateChangedCallback>>;
type DeleteStateCallback = (err?: Error | null, id?: string) => void;
type GetHistoryResult = Array<State & { id?: string }>;
type GetHistoryCallback = (
err: Error | null,
result?: GetHistoryResult,
step?: number,
sessionId?: number,
) => void;
/** Contains the return values of readDir */
interface ReadDirResult {
/** Name of the file or directory */
file: string;
/** File system stats */
stats: Partial<FsStats>;
/** Whether this is a directory or a file */
isDir: boolean;
/** Access rights */
acl?: EvaluatedFileACL;
/** Date of last modification */
modifiedAt?: number;
/** Date of creation */
createdAt?: number;
}
type ReadDirCallback = (err?: NodeJS.ErrnoException | null, entries?: ReadDirResult[]) => void;
type ReadDirPromise = Promise<ReadDirResult[]>;
type OriginalReadFileCallback = (
err?: NodeJS.ErrnoException | null,
data?: Buffer | string,
mimeType?: string,
) => void;
type OriginalReadFilePromise = Promise<{ file: string | Buffer; mimeType?: string }>;
/** Contains the return values of chownFile */
interface ChownFileResult {
/** The parent directory of the processed file or directory */
path: string;
/** Name of the file or directory */
file: string;
/** File system stats */
stats: FsStats;
/** Whether this is a directory or a file */
isDir: boolean;
/** Access rights */
acl: FileACL;
/** Date of last modification */
modifiedAt: number;
/** Date of creation */
createdAt: number;
}
type ChownFileCallback = (err?: NodeJS.ErrnoException | null, processed?: ChownFileResult[]) => void;
/** Contains the return values of rm */
interface RmResult {
/** The parent directory of the deleted file or directory */
path: string;
/** The name of the deleted file or directory */
file: string;
}
type RmCallback = (err?: NodeJS.ErrnoException | null, entries?: RmResult[]) => void;
type ChownObjectCallback = (err?: NodeJS.ErrnoException | null, list?: iobJS.Object[]) => void;
type GetKeysCallback = (err?: Error | null, list?: string[]) => void;
interface GetObjectViewItem<T extends AnyObject> {
/** The ID of this object */
id: T['_id'];
/** A copy of the object from the DB */
value: T;
}
type GetObjectViewCallback<T extends AnyObject> = (
err?: Error | null,
result?: { rows: Array<GetObjectViewItem<T>> },
) => void;
type GetObjectViewPromise<T extends AnyObject> = Promise<NonNullCallbackReturnTypeOf<GetObjectViewCallback<T>>>;
interface GetObjectListItem<T extends AnyObject> extends GetObjectViewItem<T> {
/** A copy of the object */
value: T;
/** The same as @link{value} */
doc: T;
}
type GetObjectListCallback<T extends iobJS.AnyObject> = (
err?: Error | null,
result?: { rows: GetObjectListItem<T>[] },
) => void;
type GetObjectListPromise = Promise<NonNullCallbackReturnTypeOf<GetObjectListCallback<iobJS.Object>>>;
type ExtendObjectCallback = (
err?: Error | null,
result?: { id: string; value: iobJS.Object },
id?: string,
) => void;
type GetSessionCallback = (session: Session) => void;
type Timeout = Branded<number, 'Timeout'> | null; // or null to not allow native clearTimeout
type Interval = Branded<number, 'Interval'> | null; // or null to not allow native clearInterval
/** Defines access rights for a single file */
interface FileACL {
/** Full name of the user who owns this file, e.g. "system.user.admin" */
owner: string;
/** Full name of the group who owns this file, e.g. "system.group.administrator" */
ownerGroup: string;
/** Linux-type permissions defining access to this file */
permissions: number;
}
/** Defines access rights for a single file, applied to a user or group */
interface EvaluatedFileACL extends FileACL {
/** Whether the user may read the file */
read: boolean;
/** Whether the user may write the file */
write: boolean;
}
/** Defines access rights for a single object */
interface ObjectACL {
/** Full name of the user who owns this object, e.g. "system.user.admin" */
owner: string;
/** Full name of the group who owns this object, e.g. "system.group.administrator" */
ownerGroup: string;
/** Linux-type permissions defining access to this object */
object: number;
}
/** Defines access rights for a single state object */
interface StateACL extends ObjectACL {
/** Linux-type permissions defining access to this state */
state: number;
}
/** Defines the existing object types in ioBroker */
type ObjectType =
| 'state'
| 'channel'
| 'device'
| 'folder'
| 'enum'
| 'adapter'
| 'config'
| 'group'
| 'host'
| 'instance'
| 'meta'
| 'script'
| 'user'
| 'chart'
| 'schedule'
| 'design';
// Define the naming schemes for objects, so we can provide more specific types for get/setObject
namespace ObjectIDs {
// Guaranteed meta objects
type Meta =
| `${string}.${number}`
| `${string}.${'meta' | 'admin'}`
| `${string}.meta.${string}`
| `${string}.${number}.meta.${string}`;
// Unsure, can be folder, device, channel or state
// --> We need this match to avoid matching the more specific types below
type Misc = `system.host.${string}.${string}` | `0_userdata.0.${string}`;
// Guaranteed channel objects
type Channel = `script.js.${'common' | 'global'}` | `${string}.${number}.info`;
// Either script or channel object
type ScriptOrChannel = `script.js.${string}`;
// Guaranteed state objects
type State = `system.adapter.${string}.${number}.${string}`;
// Guaranteed enum objects
type Enum = `enum.${string}`;
// Guaranteed instance objects
type Instance = `system.adapter.${string}.${number}`;
// Guaranteed adapter objects
type Adapter = `system.adapter.${string}` | `system.host.${string}.adapter.${string}`;
// Guaranteed group objects
type Group = `system.group.${string}`;
// Guaranteed user objects
type User = `system.user.${string}`;
// Guaranteed host objects
type Host = `system.host.${string}`;
// Guaranteed repository object
type Repository = 'system.repositories';
// Guaranteed config objects
type Config = 'system.certificates';
// Guaranteed system config objects
type SystemConfig = 'system.config';
// Guaranteed design objects
type Design = `_design/${string}`;
// Unsure, can be folder, device, channel or state (or whatever an adapter does)
type AdapterScoped = `${string}.${number}.${string}`;
/** All possible typed object IDs */
type Any =
| Meta
| Misc
| Channel
| ScriptOrChannel
| State
| Enum
| Instance
| Adapter
| Group
| User
| Host
| Config
| AdapterScoped;
}
type ObjectIdToObjectType<T extends string, Read extends 'read' | 'write' = 'read'> =
// State must come before Adapter or system.adapter.admin.0.foobar will resolve to AdapterObject
T extends ObjectIDs.State
? StateObject
: // Instance and Adapter must come before meta or `system.adapter.admin` will resolve to MetaObject
T extends ObjectIDs.Instance
? InstanceObject
: T extends ObjectIDs.Adapter
? AdapterObject
: T extends ObjectIDs.Channel
? ChannelObject
: T extends ObjectIDs.Meta
? MetaObject
: T extends ObjectIDs.Misc
? AdapterScopedObject
: T extends ObjectIDs.ScriptOrChannel
? ScriptObject | ChannelObject
: T extends ObjectIDs.Enum
? EnumObject
: T extends ObjectIDs.Group
? GroupObject
: T extends ObjectIDs.User
? UserObject
: T extends ObjectIDs.Host
? HostObject
: T extends ObjectIDs.Design
? DesignObject
: T extends ObjectIDs.Repository
? RepositoryObject
: T extends ObjectIDs.SystemConfig
? SystemConfigObject
: T extends ObjectIDs.Config
? OtherObject & { type: 'config' }
: T extends ObjectIDs.AdapterScoped
? AdapterScopedObject
: Read extends 'read'
? iobJS.Object
: AnyObject;
type Languages = 'en' | 'de' | 'ru' | 'pt' | 'nl' | 'fr' | 'it' | 'es' | 'pl' | 'uk' | 'zh-cn';
type Translated = { en: string } & { [lang in Languages]?: string };
/** For objects, we require the English language to be present */
type StringOrTranslated = string | Translated;
type CommonType = 'number' | 'string' | 'boolean' | 'array' | 'object' | 'mixed';
interface ObjectCommon {
/** The name of this object as a simple string or an object with translations */
name: StringOrTranslated;
/** Description of this object */
desc?: StringOrTranslated;
/** When set to true, this object may not be deleted */
dontDelete?: true;
/** When set to true, this object is only visible when expert mode is turned on in admin */
expert?: true;
/** Color attribute used in UI */
color?: string;
// Icon and role aren't defined in SCHEMA.md,
// but they are being used by some adapters
/** Icon for this object */
icon?: string;
/** role of the object */
role?: string;
}
interface StateCommon extends ObjectCommon {
/** Type of this state. See https://github.com/ioBroker/ioBroker/blob/master/doc/SCHEMA.md#state-commonrole for a detailed description */
type: CommonType;
/** minimum value */
min?: number;
/** maximum value */
max?: number;
/** the allowed interval for numeric values */
step?: number;
/** unit of the value */
unit?: string;
/** if this state is readable */
read: boolean;
/** if this state is writable */
write: boolean;
/** role of the state (used in user interfaces to indicate which widget to choose) */
role: string;
/** the default value */
def?: any;
/** the default status of the ack flag */
defAck?: boolean;
/** Configures this state as an alias for another state */
alias?: {
/** The target state id */
id:
| string
| {
read: string;
write: string;
};
/** An optional conversion function when reading, e.g. `"(val − 32) * 5/9"` */
read?: string;
/** An optional conversion function when reading, e.g. `"(val * 9/5) + 32"` */
write?: string;
};
/**
* Dictionary of possible values for this state in the form
* ```jsonc
* {
* "internal value 1": "displayed value 1",
* "internal value 2": "displayed value 2",
* // ...
* }
* ```
*
* or as an array:
* ```jsonc
* [ "value 1", "value 2", // ... ]
* ```
*
* In old ioBroker versions, this could also be a string of the form
* `"val1:text1;val2:text2"` (now deprecated)
*/
states?: Record<string, string> | string[] | string;
/** ID of a helper state indicating if the handler of this state is working */
workingID?: string;
/** attached history information */
history?: any;
/** Custom settings for this state */
custom?: Record<string, any>;
/** Custom defined properties for backward compatibility of material adapter */
material?: any;
/** Custom defined properties for backward compatibility of habpanel adapter */
habpanel?: any;
/** Custom defined properties for backward compatibility of habpanel adapter */
mobile?: any;
/**
* Settings for IOT adapters and how the state should be named in e.g., Alexa.
* The string "ignore" (deprecated please use boolean `false` instead) or boolean value `false` is a special case, causing the state to be ignored.
* A value of `null` means that the device should be removed by the IOT adapters
*/
smartName?:
| null
| false
| string
| ({ [lang in Languages]?: string } & {
/** Which kind of device it is */
smartType?: string | null;
/** Which value to set when the ON command is issued */
byON?: string | null;
});
}
interface ChannelCommon extends ObjectCommon {
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
interface DeviceCommon extends ObjectCommon {
statusStates?: {
/** State, which is truthy if a device is online */
onlineId?: string;
/** State, which is truthy if a device is offline */
offlineId?: string;
/** State, which is truthy if a device is in error state */
errorId?: string;
};
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
interface ScheduleCommon extends ObjectCommon {
enabled?: boolean;
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
interface RepositoryCommon extends ObjectCommon {
custom?: undefined;
}
interface ChartCommon extends ObjectCommon {
enabled?: boolean;
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
interface EnumCommon extends ObjectCommon {
/** The IDs of the enum members */
members?: string[];
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
interface MetaCommon extends ObjectCommon {
// Can be of type `user` for folders, where a user can store files or `folder` for adapter internal structures
type: 'meta.user' | 'meta.folder';
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
type InstanceMode = 'none' | 'daemon' | 'schedule' | 'once' | 'extension';
interface AdminUi {
/** UI type of config page inside admin UI */
config: 'html' | 'json' | 'materialize' | 'none';
/** UI type of custom tab inside admin UI */
custom?: 'json';
/** UI type of tab inside admin UI */
tab?: 'html' | 'json' | 'materialize';
}
/** Installed from attribute of instance/adapter object */
type InstalledFrom = Branded<string, 'InstalledFrom'>;
interface InstanceCommon extends AdapterCommon {
version: string;
/** The name of the host where this instance is running */
host: string;
enabled: boolean;
/** How and when this instance should be started */
mode: InstanceMode;
/**
* The starting priority of this adapter:
* - **1:** Logic adapters
* - **2:** Data providers
* - **3:** All other adapters
*/
tier?: 1 | 2 | 3;
/** Variables of this adapter must be subscribed with sendTo to enable updates */
subscribable?: boolean;
/** If compact mode is supported */
compact?: boolean;
/** If compact mode is active */
runAsCompactMode?: boolean;
/** Active compact group, instances in this group will be started in one process */
compactGroup?: number;
/** String (or array) with names of attributes in common of instance, which will not be deleted. */
preserveSettings?: string | string[];
/** Source, where this adapter has been installed from, to enable reinstalling on e.g., backup restore */
installedFrom?: InstalledFrom;
/** Arguments passed to the adapter process, this disables compact mode */
nodeProcessParams?: string[];
/** If adapter can consume log messages, like admin, javascript or logparser */
logTransporter?: boolean;
/** Optional memory limit for this instance */
memoryLimitMB?: number;
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
interface HostCommon extends ObjectCommon {
/** The display name of this host */
name: string;
/** Changeable name of the host */
title: string;
/** base64 encoded icon */
icon?: string;
installedVersion: string; // e.g. 1.2.3 (following semver)
/** The command line of the executable */
cmd: string;
hostname: string;
/** An array of IP addresses this host exposes */
address: string[]; // IPv4 or IPv6
type: 'js-controller';
platform: 'Javascript/Node.js';
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
interface HostNative {
process: {
title: string;
versions: NodeJS.ProcessVersions;
env: NodeJS.ProcessEnv;
};
os: {
hostname: string;
type: ReturnType<(typeof os)['type']>;
platform: ReturnType<(typeof os)['platform']>;
arch: ReturnType<(typeof os)['arch']>;
release: ReturnType<(typeof os)['release']>;
endianness: ReturnType<(typeof os)['endianness']>;
tmpdir: ReturnType<(typeof os)['tmpdir']>;
};
hardware: {
/** Return value of os.cpu but property `times` could be removed from every entry */
cpus: (Omit<ReturnType<(typeof os)['cpus']>[number], 'times'> &
Partial<Pick<ReturnType<(typeof os)['cpus']>[number], 'times'>>)[];
totalmem: ReturnType<(typeof os)['totalmem']>;
networkInterfaces: ReturnType<(typeof os)['networkInterfaces']>;
};
}
interface UserCommon extends ObjectCommon {
/** The username */
name: StringOrTranslated;
/** The hashed password */
password: string;
/** Whether this user is enabled */
enabled: boolean;
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
interface GroupCommon extends ObjectCommon {
/** The name of this group */
name: StringOrTranslated;
/** The users of this group */
members: ObjectIDs.User[]; // system.user.name, ...
/** The default permissions of this group */
acl: Omit<PermissionSet, 'user' | 'groups'>;
/** A group can be disabled, if missing, a group is active */
enabled?: boolean;
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
interface ScriptCommon extends ObjectCommon {
name: string;
/** Defines the type of the script, e.g., TypeScript/ts, Javascript/js or Blockly */
engineType: 'TypeScript/ts' | 'Blockly' | 'Rules' | 'Javascript/js';
/** The instance id of the instance which executes this script */
engine: string;
/** The source code of this script */
source: string;
debug: boolean;
verbose: boolean;
/** Whether this script should be executed */
enabled: boolean;
/** Is used to determine whether a script has changed and needs to be recompiled */
sourceHash?: string;
/** If the script uses a compiled language like TypeScript, this contains the compilation output */
compiled?: string;
/** If the script uses a compiled language like TypeScript, this contains the generated declarations (global scripts only) */
declarations?: string;
// Make it possible to narrow the object type using the custom property
custom?: undefined;
}
type WelcomeScreenEntry =
| string
| {
link: string;
name: string;
img: string;
color: string;
order?: number;
};
/**
* Object which defines if the adapter supports receiving messages via sendTo.
* Additionally, it defines if specific messages are supported.
* If one property is enabled, the object `system.adapter.<adapterName>.<adapterInstance>.messagebox will be created to send messages to the adapter (used for email, pushover, etc...)
*/
interface SupportedMessages {
/** If custom messages are supported (same as legacy messagebox) */
custom?: boolean;
/** If notification handling is supported, for information, see https://github.com/foxriver76/ioBroker.notification-manager#requirements-for-messaging-adapters */
notifications?: boolean;
/** If adapter supports signal stopInstance. Use number if you need more than 1000 ms for stop routine. The signal will be sent before stop to the adapter. (used if problems occurred with SIGTERM). */
stopInstance?: boolean | number;
/** If adapter supports the device manager and thus responds to the corresponding messages */
deviceManager?: boolean;
/** If adapter supports getHistory message. */
getHistory?: boolean;
}
type AutoUpgradePolicy = 'none' | 'patch' | 'minor' | 'major';
interface VisWidget {
i18n: 'component' | true | Translated;
name: string;
url: string;
components: string[];
/** The vis widget does not support the listed major versions of vis */
ignoreInVersions: number[];
}
type PaidLicenseType = 'paid' | 'commercial' | 'limited';
interface LicenseInformationFree {
/** License of the software */
license?: string;
/** Use 'paid' for adapters which do not work without a paid license. Use 'commercial' for adapters which require a license for commercial use only. Use 'limited' if some functionalities are not available without a paid license. */
type: 'free';
/**
* Hyperlink, where information about the license can be found. For non-free licenses, the linked page should contain information about free features (if applicable), time of validity, link to shop and seller information.
* This is required if the license type is different from 'free'. For 'free' licenses, an optional link to the license file can be placed here.
*/
link?: string;
}
interface LicenseInformationWithPayment {
/** License of the software */
license?: string;
/** Use 'paid' for adapters which do not work without a paid license. Use 'commercial' for adapters which require a license for commercial use only. Use 'limited' if some functionalities are not available without a paid license. */
type: PaidLicenseType;
/**
* Hyperlink, where information about the license can be found. For non-free licenses, the linked page should contain information about free features (if applicable), time of validity, link to shop and seller information.
* This is required if the license type is different from 'free'. For 'free' licenses, an optional link to the license file can be placed here.
*/
link: string;
}
type LicenseInformation = LicenseInformationFr