UNPKG

iobroker.javascript

Version:
1,373 lines (1,226 loc) 74 kB
// import all modules that are available in the sandbox // this has a nice side effect that we may augment the global scope import * as child_process from "child_process"; import * as os from "os"; type EmptyCallback = () => void | Promise<void>; type ErrorCallback = (err?: string) => void | Promise<void>; type GenericCallback<T> = (err?: string | 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 LogCallback = (msg: any) => 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 { enum StateQuality { good = 0x00, // or undefined or null bad = 0x01, general_problem = 0x01, general_device_problem = 0x41, general_sensor_problem = 0x81, device_not_connected = 0x42, sensor_not_connected = 0x82, device_reports_error = 0x44, sensor_reports_error = 0x84, } type PrimitiveTypeStateValue = string | number | boolean; type StateValue = null | PrimitiveTypeStateValue | PrimitiveTypeStateValue[] | Record<string, any>; interface State<T extends StateValue = any> { /** The value of the state. */ val: T; /** 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; /** Optional time in seconds after which the state is reset to null */ expire?: number; /** Optional quality of the state value */ q?: StateQuality; /** Optional comment */ c?: string; /** Discriminant property to switch between AbsentState and State<T> */ notExist: undefined; } type SettableState = AtLeastOne<State>; interface AbsentState { val: null; notExist: true; ack: undefined; ts: undefined; lc: undefined; from: undefined; expire: undefined; q: undefined; c: undefined; } type Languages = 'en' | 'de' | 'ru' | 'pt' | 'nl' | 'fr' | 'it' | 'es' | 'pl' | 'uk' | 'zh-cn'; type StringOrTranslated = string | { [lang in Languages]?: string; }; type CommonType = "number" | "string" | "boolean" | "array" | "object" | "mixed" | "file"; /** 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 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'; // 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}`; // 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 config objects type Config = `system.${"certificates" | "config" | "repositories"}`; // 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", O = // 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.Config ? OtherObject & { type: "config" } : T extends ObjectIDs.AdapterScoped ? AdapterScopedObject : iobJS.AnyObject // When reading objects, we should be less strict, so working with the return type is less of a pain to work with > = Read extends "read" ? AnyOf<O> : O; interface ObjectCommon { /** The name of this object as a simple string or an object with translations */ name: 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; // 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 StateCommonAlias { /** The target state id or two target states used for reading and writing values */ 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; } 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; /** description of this state */ desc?: StringOrTranslated; /** 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?: StateCommonAlias; /** * Dictionary of possible values for this state in the form * <pre> * { * "internal value 1": "displayed value 1", * "internal value 2": "displayed value 2", * ... * } * </pre> * In old ioBroker versions, this could also be a string of the form * "val1:text1;val2:text2" (now deprecated) */ states?: Record<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>; /** * Settings for IOT adapters and how the state should be named in e.g., Alexa. * The string "ignore" is a special case, causing the state to be ignored. */ smartName?: string | ({ [lang in Languages]?: string; } & { /** Which kind of device this is */ smartType?: string | null; /** Which value to set when the ON command is issued */ byOn?: string | null; }); } interface ChannelCommon extends ObjectCommon { /** description of this channel */ desc?: string; // Make it possible to narrow the object type using the custom property custom?: undefined; } interface DeviceCommon extends ObjectCommon { // TODO: any other definition for device? // 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 { // Meta-objects have to additional CommonTypes type: CommonType | "meta.user" | "meta.folder"; // Make it possible to narrow the object type using the custom property custom?: undefined; } type InstanceMode = 'none' | 'daemon' | 'subscribe' | 'schedule' | 'once' | 'extension'; interface InstanceCommon extends ObjectCommon { /** The name of the host where this instance is running */ host: string; enabled: boolean; /** How and when this instance should be started */ mode: InstanceMode; // 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; title: 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: Record<string, string>; }; 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: { cpus: ReturnType<typeof os["cpus"]>; totalmem: ReturnType<typeof os["totalmem"]>; networkInterfaces: ReturnType<typeof os["networkInterfaces"]>; }; } interface UserCommon extends ObjectCommon { /** The username */ name: string; /** 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: string; /** The users of this group */ members: string[]; // system.user.name, ... /** The default permissions of this group */ acl: Omit<PermissionSet, "user" | "groups">; // 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: string; /** 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; }; interface AdapterCommon extends ObjectCommon { /** Custom attributes to be shown in admin in the object browser */ adminColumns?: any[]; /** Settings for custom Admin Tabs */ adminTab?: { name?: string; /** Icon name for FontAwesome */ "fa-icon"?: string; /** If true, the Tab is not reloaded when the configuration changes */ ignoreConfigUpdate?: boolean; /** Which URL should be loaded in the tab. Supports placeholders like http://%ip%:%port% */ link?: string; /** If true, only one instance of this tab will be created for all instances */ singleton?: boolean; }; allowInit?: boolean; /** Possible values for the instance mode (if more than one is possible) */ availableModes?: InstanceMode[]; /** Whether this adapter includes custom blocks for Blockly. If true, `admin/blockly.js` must exist. */ blockly?: boolean; /** Where the adapter will get its data from. Set this together with @see dataSource */ connectionType?: "local" | "cloud"; /** If true, this adapter can be started in compact mode (in the same process as other adpaters) */ compact?: boolean; /** The directory relative to iobroker-data where the adapter stores the data. Supports the placeholder `%INSTANCE%`. This folder will be backed up and restored automatically. */ dataFolder?: string; /** How the adapter will mainly receive its data. Set this together with @see connectionType */ dataSource?: "poll" | "push" | "assumption"; /** A record of ioBroker adapters (including "js-controller") and version ranges which are required for this adapter. */ dependencies?: Array<Record<string, string>>; /** Which files outside of the README.md have documentation for the adapter */ docs?: Partial<Record<Languages, string | string[]>>; /** Whether new instances should be enabled by default. *Should* be `false`! */ enabled: boolean; /** If true, all previous data in the target directory (web) should be deleted before uploading */ eraseOnUpload?: boolean; /** URL of an external icon that is shown for adapters that are not installed */ extIcon?: string; /** Whether this adapter responds to `getHistory` messages */ getHistory?: boolean; /** Filename of the local icon which is shown for installed adapters. Should be located in the `admin` directory */ icon?: string; /** Which version of this adapter is installed */ installedVersion: string; keywords?: string[]; /** A dictionary of links to web services this adapter provides */ localLinks?: Record<string, string>; /** @deprecated Use @see localLinks */ localLink?: string; logLevel?: LogLevel; /** Whether this adapter receives logs from other hosts and adapters (e.g., to strore them somewhere) */ logTransporter?: boolean; /** Path to the start file of the adapter. Should be the same as in `package.json` */ main?: string; /** Whether the admin tab is written in materialize style. Required for Admin 3+ */ materializeTab: boolean; /** Whether the admin configuration dialog is written in materialize style. Required for Admin 3+ */ materialize: boolean; /** If `true`, the object `system.adapter.<adaptername>.<adapterinstance>.messagebox will be created to send messages to the adapter (used for email, pushover, etc...) */ messagebox?: true; mode: InstanceMode; /** Name of the adapter (without leading `ioBroker.`) */ name: string; /** If `true`, no configuration dialog will be shown */ noConfig?: true; /** If `true`, this adapter's instances will not be shown in the admin overview screen. Useful for icon sets and widgets... */ noIntro?: true; /** Set to `true` if the adapter is not available in the official ioBroker repositories. */ noRepository?: true; /** If `true`, manual installation from GitHub is not possible */ nogit?: true; /** If `true`, this adapter cannot be deleted or updated manually. */ nondeletable?: true; /** If `true`, this "adapter" only contains HTML files and no main executable */ onlyWWW?: boolean; /** Used to configure native (OS) dependencies of this adapter that need to be installed with system package manager before installing the adapter */ osDependencies?: { /** For OSX */ darwin: string[]; /** For Linux */ linux: string[]; /** For Windows */ win32: string[]; }; /** Which OSes this adapter supports */ os?: "linux" | "darwin" | "win32" | Array<("linux" | "darwin" | "win32")>; platform: "Javascript/Node.js"; /** The keys of common attributes (e.g. `history`) which are not deleted in a `setObject` call even if they are not present. Deletion must be done explicitly by setting them to `null`. */ preserveSettings?: string | string[]; /** Which adapters must be restarted after installing or updating this adapter. */ restartAdapters?: string[]; /** If the adapter runs in `schedule` mode, this contains the CRON */ schedule?: string; serviceStates?: boolean | string; /** Whether this adapter may only be installed once per host */ singletonHost?: boolean; /** Whether this adapter may only be installed once in the whole system */ singleton?: boolean; /** Whether the adapter must be stopped before an update */ stopBeforeUpdate?: boolean; /** Overrides the default timeout that ioBroker will wait before force-stopping the adapter */ stopTimeout?: number; subscribable?: boolean; subscribe?: any; // ? /** If `true`, this adapter provides custom per-state settings. Requires a `custom_m.html` file in the `admin` directory. */ supportCustoms?: boolean; /** Whether the adapter supports the signal stopInstance via messagebox */ supportStopInstance?: boolean; /** The translated names of this adapter to be shown in the admin UI */ titleLang?: Record<Languages, string>; /** @deprecated The name of this adapter to be shown in the admin UI. Use @see titleLang instead. */ title?: string; /** The type of this adapter */ type?: string; /** If `true`, the `npm` package must be installed with the `--unsafe-perm` flag */ unsafePerm?: true; /** The available version in the ioBroker repo. */ version: string; /** If `true`, the adapter will be started if any value is written into `system.adapter.<name>.<instance>.wakeup. Normally, the adapter should stop after processing the event. */ wakeup?: boolean; /** Include the adapter version in the URL of the web adapter, e.g. `http://ip:port/1.2.3/material` instead of `http://ip:port/material` */ webByVersion?: boolean; /** Whether the web server in this adapter can be extended with plugin/extensions */ webExtendable?: boolean; /** Relative path to a module that contains an extension for the web adapter. Use together with @see native.webInstance to configure which instances this affects */ webExtension?: string; webPreSettings?: any; // ? webservers?: any; // ? /** A list of pages that should be shown on the "web" index page */ welcomeScreen?: WelcomeScreenEntry[]; /** A list of pages that should be shown on the ioBroker cloud index page */ welcomeScreenPro?: WelcomeScreenEntry[]; wwwDontUpload?: boolean; // Make it possible to narrow the object type using the custom property custom?: undefined; } interface OtherCommon extends ObjectCommon { [propName: string]: any; // Make it possible to narrow the object type using the custom property custom?: undefined; } /* Base type for Objects. Should not be used directly */ interface BaseObject { /** The ID of this object */ _id: string; type: ObjectType; // specified in the derived interfaces // Ideally we would limit this to JSON-serializable objects, but TypeScript doesn't allow this // without bugging users to change their code --> https://github.com/microsoft/TypeScript/issues/15300 native: Record<string, any>; common: Record<string, any>; enums?: Record<string, string>; acl?: ObjectACL; from?: string; /** The user who created or updated this object */ user?: string; ts?: number; } interface StateObject extends BaseObject { type: 'state'; common: StateCommon; acl?: StateACL; /** The IDs of enums this state is assigned to. For example ["enum.functions.Licht","enum.rooms.Garten"] */ enumIds?: string[]; /** The names of enums this state is assigned to. For example ["Licht","Garten"] */ enumNames?: Array<iobJS.StringOrTranslated>; } interface PartialStateObject extends Partial<Omit<StateObject, 'common' | 'acl'>> { common?: Partial<StateCommon>; acl?: Partial<StateACL>; } interface ChannelObject extends BaseObject { type: 'channel'; common: ChannelCommon; } interface PartialChannelObject extends Partial<Omit<ChannelObject, 'common'>> { common?: Partial<ChannelCommon>; } interface DeviceObject extends BaseObject { type: 'device'; common: DeviceCommon; } interface PartialDeviceObject extends Partial<Omit<DeviceObject, 'common'>> { common?: Partial<DeviceCommon>; } interface FolderObject extends BaseObject { type: 'folder'; // Nothing is set in stone here, so start with allowing every property common: OtherCommon; } interface PartialFolderObject extends Partial<Omit<FolderObject, 'common'>> { common?: Partial<OtherCommon>; } interface EnumObject extends BaseObject { type: 'enum'; common: EnumCommon; } interface PartialEnumObject extends Partial<Omit<EnumObject, 'common'>> { common?: Partial<EnumCommon>; } interface MetaObject extends BaseObject { type: 'meta'; common: MetaCommon; } interface PartialMetaObject extends Partial<Omit<MetaObject, 'common'>> { common?: Partial<MetaCommon>; } interface InstanceObject extends BaseObject { type: 'instance'; common: InstanceCommon; } interface PartialInstanceObject extends Partial<Omit<InstanceObject, 'common'>> { common?: Partial<InstanceCommon>; } interface AdapterObject extends BaseObject { type: 'adapter'; common: AdapterCommon; /** An array of `native` properties which cannot be accessed from outside the defining adapter */ protectedNative?: string[]; /** Like protectedNative, but the properties are also encrypted and decrypted automatically */ encryptedNative?: string[]; } interface PartialAdapterObject extends Partial<Omit<AdapterObject, 'common'>> { common?: Partial<AdapterCommon>; } interface HostObject extends BaseObject { type: 'host'; common: HostCommon; native: HostNative; } interface PartialHostObject extends Partial<Omit<HostObject, 'common' | 'native'>> { common?: Partial<HostCommon>; native?: Partial<HostNative>; } interface UserObject extends BaseObject { type: 'user'; common: UserCommon; } interface PartialUserObject extends Partial<Omit<UserObject, 'common'>> { common?: Partial<UserCommon>; } interface GroupObject extends BaseObject { type: 'group'; common: GroupCommon; } interface PartialGroupObject extends Partial<Omit<GroupObject, 'common'>> { common?: Partial<GroupCommon>; } interface ScriptObject extends BaseObject { type: 'script'; common: ScriptCommon; } interface PartialScriptObject extends Partial<Omit<ScriptObject, 'common'>> { common?: Partial<ScriptCommon>; } interface OtherObject extends BaseObject { type: 'config' | 'chart'; common: OtherCommon; } interface PartialOtherObject extends Partial<Omit<OtherObject, 'common'>> { common?: Partial<OtherCommon>; } type AnyObject = | StateObject | ChannelObject | DeviceObject | FolderObject | EnumObject | MetaObject | HostObject | AdapterObject | InstanceObject | UserObject | GroupObject | ScriptObject | OtherObject; type AnyPartialObject = | PartialStateObject | PartialChannelObject | PartialDeviceObject | PartialFolderObject | PartialEnumObject | PartialMetaObject | PartialHostObject | PartialAdapterObject | PartialInstanceObject | PartialUserObject | PartialGroupObject | PartialScriptObject | PartialOtherObject; /** All objects that usually appear in an adapter scope */ type AdapterScopedObject = FolderObject | DeviceObject | ChannelObject | StateObject; // For all objects that are exposed to the user we need to tone the strictness down. // Otherwise, every operation on objects becomes a pain to work with type Object = AnyObject; // In set[Foreign]Object[NotExists] methods, the ID and acl of the object is optional type SettableObjectWorker<T> = T extends AnyObject ? Omit<T, '_id' | 'acl'> & { _id?: T['_id']; acl?: T['acl']; } : never; // in extend[Foreign]Object, most properties are optional type PartialObjectWorker<T> = T extends AnyObject ? AnyPartialObject & { type?: T["type"] } : never; type PartialObject<T extends AnyObject = AnyObject> = PartialObjectWorker<T>; // Convenient definitions for manually specifying settable object types type SettableObject<T extends AnyObject = AnyObject> = SettableObjectWorker<T>; type SettableStateObject = SettableObject<StateObject>; type SettableChannelObject = SettableObject<ChannelObject>; type SettableDeviceObject = SettableObject<DeviceObject>; type SettableFolderObject = SettableObject<FolderObject>; type SettableEnumObject = SettableObject<EnumObject>; type SettableMetaObject = SettableObject<MetaObject>; type SettableHostObject = SettableObject<HostObject>; type SettableAdapterObject = SettableObject<AdapterObject>; type SettableInstanceObject = SettableObject<InstanceObject>; type SettableUserObject = SettableObject<UserObject>; type SettableGroupObject = SettableObject<GroupObject>; type SettableScriptObject = SettableObject<ScriptObject>; type SettableOtherObject = SettableObject<OtherObject>; /** Represents the change of a state */ interface ChangedStateObject<TOld extends StateValue = any, TNew extends StateValue = TOld> extends StateObject { common: StateCommon; native: Record<string, any>; id?: string; name?: string; channelId?: string; channelName?: string; deviceId?: string; deviceName?: string; /** The IDs of enums this state is assigned to. For example ["enum.functions.Licht","enum.rooms.Garten"] */ enumIds?: string[]; /** The names of enums this state is assigned to. For example ["Licht","Garten"] */ enumNames?: Array<iobJS.StringOrTranslated>; /** new state */ state: State<TNew>; /** @deprecated Use state instead **/ newState: State<TNew>; /** previous state */ oldState: State<TOld>; /** Name of the adapter instance which set the value, e.g. "system.adapter.web.0" */ from?: string; /** Unix timestamp. Default: current time */ ts?: number; /** Unix timestamp of the last time the value changed */ lc?: number; /** Direction flag: false for desired value and true for actual value. Default: false. */ ack?: boolean; } type GetStateCallback<T extends StateValue = any> = (err?: string | null, state?: State<T> | AbsentState) => void | Promise<void>; type ExistsStateCallback = (err?: string | null, exists?: Boolean) => void | Promise<void>; type SetStateCallback = (err?: string | null, id?: string) => void | Promise<void>; type SetStatePromise = Promise<NonNullCallbackReturnTypeOf<SetStateCallback>>; type StateChangeHandler<TOld extends StateValue = any, TNew extends TOld = any> = (obj: ChangedStateObject<TOld, TNew>) => void | Promise<void>; type ObjectChangeHandler = (id: string, obj: iobJS.Object) => void | Promise<void>; type FileChangeHandler<WithFile extends boolean> = // Variant 1: WithFile is false, data/mimeType is definitely not there [WithFile] extends [false] ? (id: string, fileName: string, size: number, data?: undefined, mimeType?: undefined) => void | Promise<void> // Variant 2: WithFile is true, data (and mimeType?) is definitely there : [WithFile] extends [true] ? (id: string, fileName: string, size: number, data: Buffer | string, mimeType?: string) => void | Promise<void> // Variant 3: WithFile is not known, data/mimeType might be there : (id: string, fileName: string, size: number, data?: Buffer | string, mimeType?: string) => void | Promise<void>; type SetObjectCallback = (err?: string | null, obj?: { id: string }) => void | Promise<void>; type SetObjectPromise = Promise<NonNullCallbackReturnTypeOf<SetObjectCallback>>; type GetObjectCallback<T extends string = string> = (err?: string | null, obj?: ObjectIdToObjectType<T> | null) => void; type GetObjectPromise<T extends string = string> = Promise<CallbackReturnTypeOf<GetObjectCallback<T>>>; type LogLevel = "silly" | "debug" | "info" | "warn" | "error" | "force"; type ReadFileCallback = (err?: string | null, file?: Buffer | string, mimeType?: string) => void | Promise<void>; type ReadFilePromise = Promise<NonNullCallbackReturnTypeOf<ReadFileCallback>>; /** Callback information for a passed message */ interface MessageCallbackInfo { /** The original message payload */ message: string | object; /** ID of this callback */ id: number; // ??? ack: boolean; /** Timestamp of this message */ time: number; } type MessageCallback = (result?: any) => void | Promise<void>; interface SendToOptions { /** Method throws or calls error cb, if callback not called in time, works for single targets only */ timeout?: number; } interface Subscription { name: string; pattern: string | RegExp | string[] | iobJS.SubscribeOptions | iobJS.SubscribeTime | iobJS.AstroSchedule; } interface SubscribeOptions { /** "and" or "or" logic to combine the conditions (default: "and") */ logic?: "and" | "or"; /** name is equal or matches to given one or name marches to any item in given list */ id?: string | string[] | SubscribeOptions[] | RegExp | RegExp[]; /** name is equal or matches to given one */ name?: string | string[] | RegExp; /** type of change */ change?: "eq" | "ne" | "gt" | "ge" | "lt" | "le" | "any"; val?: StateValue; /** New value must not be equal to given one */ valNe?: StateValue; /** New value must be greater than given one */ valGt?: number; /** New value must be greater or equal to given one */ valGe?: number; /** New value must be smaller than given one */ valLt?: number; /** New value must be smaller or equal to given one */ valLe?: number; /** Acknowledged state of new value is equal to given one */ ack?: boolean; /** Previous value must be equal to given one */ oldVal?: StateValue; /** Previous value must be not equal to given one */ oldValNe?: StateValue; /** Previous value must be greater than given one */ oldValGt?: number; /** Previous value must be greater or equal given one */ oldValGe?: number; /** Previous value must be smaller than given one */ oldValLt?: number; /** Previous value must be smaller or equal to given one */ oldValLe?: number; /** Acknowledged state of previous value is equal to given one */ oldAck?: boolean; /** New value time stamp must be equal to given one (state.ts == ts) */ ts?: number; /** New value time stamp must be not equal to the given one (state.ts != ts) */ tsGt?: number; /** New value time stamp must be greater than given value (state.ts > ts) */ tsGe?: number; /** New value time stamp must be greater or equal to given one (state.ts >= ts) */ tsLt?: number; /** New value time stamp must be smaller than given one (state.ts < ts) */ tsLe?: number; /** Previous time stamp must be equal to given one (oldState.ts == ts) */ oldTs?: number; /** Previous time stamp must be not equal to the given one (oldState.ts != ts) */ oldTsGt?: number; /** Previous time stamp must be greater than the given value (oldState.ts > ts) */ oldTsGe?: number; /** Previous time stamp must be greater or equal to given one (oldState.ts >= ts) */ oldTsLt?: number; /** Previous time stamp must be smaller than given one (oldState.ts < ts) */ oldTsLe?: number; /** Last change time stamp must be equal to given one (state.lc == lc) */ lc?: number; /** Last change time stamp must be not equal to the given one (state.lc != lc) */ lcGt?: number; /** Last change time stamp must be greater than the given value (state.lc > lc) */ lcGe?: number; /** Last change time stamp must be greater or equal to given one (state.lc >= lc) */ lcLt?: number; /** Last change time stamp must be smaller than given one (state.lc < lc) */ lcLe?: number; /** Previous last change time stamp must be equal to given one (oldState.lc == lc) */ oldLc?: number; /** Previous last change time stamp must be not equal to the given one (oldState.lc != lc) */ oldLcGt?: number; /** Previous last change time stamp must be greater than the given value (oldState.lc > lc) */ oldLcGe?: number; /** Previous last change time stamp must be greater or equal to given one (oldState.lc >= lc) */ oldLcLt?: number; /** Previous last change time stamp must be smaller than given one (oldState.lc < lc) */ oldLcLe?: number; /** Channel ID must be equal or match to given one */ channelId?: string | string[] | RegExp; /** Channel name must be equal or match to given one */ channelName?: string | string[] | RegExp; /** Device ID must be equal or match to given one */ deviceId?: string | string[] | RegExp; /** Device name must be equal or match to given one */ deviceName?: string | string[] | RegExp; /** State belongs to given enum or one enum ID of state satisfy the given regular expression */ enumId?: string | string[] | RegExp; /** State belongs to given enum or one enum name of state satisfy the given regular expression */ enumName?: string | string[] | RegExp; /** New value is from defined adapter */ from?: string | string[] | RegExp; /** New value is not from defined adapter */ fromNe?: string | string[] | RegExp; /** Old value is from defined adapter */ oldFrom?: string | string[] | RegExp; /** Old value is not from defined adapter */ oldFromNe?: string | string[] | RegExp; } interface QueryResult extends Iterable<string> { /** State-ID */ [index: number]: string; /** Number of matched states */ length: number; /** Contains the error if one happened */ error?: string; /** * Executes a function for each state id in the result array * The execution is canceled if a callback returns false */ each(callback?: (id: string, index: number) => boolean | void | Promise<void>): this; /** * Returns the first state found by this query. * If the adapter is configured to subscribe to all states on start, * this can be called synchronously and immediately returns the state. * Otherwise, you need to provide a callback. */ getState<T extends StateValue = any>(callback: GetStateCallback<T>): void; getState<T extends StateValue = any>(): State<T> | null | undefined; getStateAsync<T extends StateValue = any>(): Promise<State<T> | null | undefined>; /** * Sets all queried states to the given value. */ setState(state: State | StateValue | SettableState, ack?: boolean, callback?: SetStateCallback): this; setStateAsync(state: State | StateValue | SettableState, ack?: boolean): Promise<void>; setStateDelayed(state: any, isAck?: boolean, delay?: number, clearRunning?: boolean, callback?: SetStateCallback): this; /** * Sets all queried states to the given value only if the value really changed. */ setStateChanged(state: State | StateValue | SettableState, ack?: boolean, callback?: SetStateCallback): this; setStateChangedAsync(state: State | StateValue | SettableState, ack?: boolean): Promise<void>; /** * Subscribes the given callback to changes of the matched states. */ on(callback: StateChangeHandler): this; } /** * * "sunrise": sunrise (top edge of the sun appears on the horizon) * * "sunriseEnd": sunrise ends (bottom edge of the sun touches the horizon) * * "goldenHourEnd": morning golden hour (soft light, best time for photography) ends * * "solarNoon": solar noon (sun is in the highest position) * * "goldenHour": evening golden hour starts * * "sunsetStart": sunset starts (bottom edge of the sun touches the horizon) * * "sunset": sunset (sun disappears below the horizon, evening civil twilight starts) * * "dusk": dusk (evening nautical twilight starts) * * "nauticalDusk": nautical dusk (evening astronomical twilight starts) * * "night": night starts (dark enough for astronomical observations) * * "nightEnd": night ends (morning astronomical twilight starts) * * "nauticalDawn": nautical dawn (morning nautical twilight starts) * * "dawn": dawn (morning nautical twilight ends, morning civil twilight starts) * * "nadir": nadir (darkest moment of the night, sun is in the lowest position) */ type AstroPattern = "sunrise" | "sunriseEnd" | "goldenHourEnd" | "solarNoon" | "goldenHour" | "sunsetStart" | "sunset" | "dusk" | "nauticalDusk" | "night" | "nightEnd" | "nauticalDawn" | "dawn" | "nadir"; interface AstroSchedule { astro: AstroPattern; /** * Shift to the astro schedule. */ shift?: number; } interface AstroDate { astro: AstroPattern; /** Offset to the astro event in minutes */ offset?: number; /** Date for which the astro time is wanted */ date?: Date; } /** * from https://github.com/node-schedule/node-schedule */ interface ScheduleRule { /** * Day of the month. */ date?: number | number[] | string | string[]; /** * Day of the week. */ dayOfWeek?: number | number[] | string | string[]; /** * Hour. */ hour?: number | number[] | string | string[]; /** * Minute. */ minute?: number | number[] | string | string[]; /** * Month. */ month?: number | number[] | string | string[]; /** * Second. */ second?: number | number[] | string | string[]; /** * Year. */ year?: number | number[] | string | string[]; /** * timezone which should be used * https://github.com/moment/moment-timezone */ tz?: string; } /** * from https://github.com/node-schedule/node-schedule */ interface ScheduleRuleConditional { /** * set a start time for schedule * a Data object or a dateString resp a number in milliseconds which can create a Date object */ start?: Date | string | number; /** * set an end time for schedule * a Data object or a dateString resp a number in milliseconds which can create a Date object */ end?: Date | string | number; /** * timezone which should be used * https://github.com/moment/moment-timezone */ tz?: string; /** * scheduling rule * schedule rule, a Data object or a dateString resp a number in milliseconds which can create a Date object */ rule: ScheduleRule | Date | string | number; } interface ScheduleStatus { type: string; pattern?: string; scriptName: string; id: string; } interface LogMessage { severity: LogLevel; // severity ts: number; // timestamp as Date.now() message: string; // message from: string; // origin of the message } type SchedulePattern = ScheduleRule | ScheduleRuleConditional | Date | string | number; interface SubscribeTime { time: SchedulePattern; } interface StateTimer { id: number; left: number; delay: number; val: any; ack: boolean; } type MessageSubscribeID = number; interface MessageTarget { /** Javascript Instance */ instance?: string; /** Script name */ script?: string; /** Message name */ message: string; } interface HttpRequestOptions { timeout?: number; responseType?: "text" | "arraybuffer"; basicAuth?: { user: string; password: string; }, bearerAuth?: string; headers?: Record<string, string>; } type HttpResponseCallback = (err?: string | null, response?: iobJS.httpResponse) => void | Promise<void>; interface httpResponse { responseCode: number; data: string; headers: Record<string, string>; } } // end namespace iobJS // ======================================================= // available functions in the sandbox // ======================================================= /** * The instance number of the JavaScript adapter this script runs in */ const instance: number; /** * The name of the current script */ // @ts-ignore We need this variable, although it conflicts with lib.es6 const name: string; /** * The name of the current script */ const scriptName: string; /** * Absolute path to iobroker-data directory in file system */ const defaultDataDir: string; /** * Status of verbose mode */ const verbose: boolean; /** * Queries all states with the given selector * @param selector See @link{https://github.com/ioBroker/ioBroker.javascript#---selector} for a description */ // @ts-ignore We need this function, although it conflicts with vue function $(selector: string): iobJS.QueryResult; /** * Prints a message in the ioBroker log * @param message The message to print * @param severity (optional) severity of the message. default = "info" */ function log(message: any, severity?: iobJS.LogLevel): void; // console functions // @ts-ignore We need this variable, although it conflicts with the node typings namespace console { /** log a message with info level */ function log(message: any): void; /** log a message with debug level */ function debug(message: any): void; /** log a message with info level (default output level for all adapters) */ function info(message: any): void; /** log a message with warning severity */ function warn(message: any): void; /** log a message with error severity */ function error(message: any): void; } /** * Executes a system command */ const exec: typeof import("child_process").exec; /** * Sends an email using the email adapter. * See the adapter documentation for a description of the msg parameter. * * @deprecated Use @see sendTo */ function email(msg: any): void; /** * Sends a pushover message using the pushover adapter. * See the adapter documentation for a description of the msg parameter. * * @deprecated Use @see sendTo */ function pushover(msg: any): void; function httpGet(url: string, callback: iobJS.HttpResponseCallback): void; function httpGet(url: string, options: iobJS.HttpRequestOptions, callback: iobJS.HttpResponseCallback): void; function httpGetAsync(url: string): Promise<iobJS.httpResponse>; function httpGetAsync(url: string, options: iobJS.HttpRequestOptions): Promise<iobJS.httpResponse>; function httpPost(url: string, data: object | string, callback: iobJS.HttpResponseCallback): void; function httpPost(url: string, data: object | string, options: iobJS.HttpRequestOptions, callback: iobJS.HttpResponseCallback): void; function httpPostAsync(url: string, data: object | string): Promise<iobJS.httpResponse>; function httpPostAsync(url: string, data: object | string, options: iobJS.HttpRequestOptions): Promise<iobJS.httpResponse>; /** * Subscribe to the changes of the matched states. */ function on(pattern: string | RegExp | string[], handler: iobJS.StateChangeHandler): any; function on( astroOrScheduleOrOptions: iobJS.AstroSchedule | iobJS.SubscribeTime | iobJS.SubscribeOptions, handler: iobJS.StateChangeHandler ): any; /** * Subscribe to the changes of the matched states. */ function subscribe(pattern: string | RegExp | string[], handler: iobJS.StateChangeHandler): any; function subscribe( astroOrScheduleOrOptions: iobJS.AstroSchedule | iobJS.SubscribeTime | iobJS.SubscribeOptions, handler: iobJS.StateChangeHandler ): any; /** * Subscribe to the changes of the matched files. * The return value can be used for offFile later * @param id ID of meta-object, like `vis.0` * @param filePattern File name or file pattern, like `main/*` * @param withFile If the content of the file must be returned in callback (high usage of memory) * @param handler Callback: function (id, fileName, size, data, mimeType) {} */ function onFile<WithFile extends boolean>(id: string, filePattern: string | string[], withFile: WithFile, handler: iobJS.FileChangeHandler<WithFile>): any; function onFile(id: string, filePattern: string | string[], handler: iobJS.FileChangeHandler<false>): any; /** * Un-subscribe from the changes of the matched files. * @param id ID of meta-object, like `vis.0`. You can provide here can be a returned object from onFile. In this case, no filePattern required. * @param filePattern File name or file pattern, like `main/*` */ function offFile(id: string | any, filePattern?: string | string[]): boolean; /** * Registers a one-time subscription which automatically unsubscribes after the first invocation */ function once( pattern: string | RegExp | string[] | iobJS.AstroSchedule | iobJS.SubscribeTime | iobJS.SubscribeOptions, handler: iobJS.StateChangeHan