UNPKG

lavva.exalushome

Version:

Library implementing communication and abstraction layers for ExalusHome system

357 lines (297 loc) 14.7 kB
# ExalusHome library for Lavva ## Library installation: If you want to use this library in any JavaScript or TypeScript project you can use npm to install it as package from npm repository. For that you will have to use command: ``` npm install lavva.exalushome ``` or ``` yarn add lavva.exalushome ``` ## Initialization: If you have installed this package then you have to initialize this library first before usage. To do this, you have to call: ```typescript import { Api } from 'lavva.exalushome'; const api = Api.Init(); ``` ## Getting services: This library implements controller APIs as a group of services that implement different functionalities. Currently we have services as: ```ts IExalusConnectionService IDevicesService ILocalStorageService IWebApiCacheService IUsersService ISessionService ILoggerService IControllerConfigurationService IChannelsGroupsService IRemoteStorageService ... ``` To get any service that is registered in dependency container you can use: ```typescript const api = Api.Get<TInterface>(ServiceClassName); //ex: import { LoggerService } from 'lavva.exalushome/build/js/Services/Logging/LoggerService'; import { ILoggerService } from 'lavva.exalushome/build/js/Services/Logging/ILoggerService'; const logger = Api.Get<ILoggerService>(LoggerService.ServiceName); ``` Where as generic T parameter you have to put the iterface that is used by given service and as the (ServiceClassName) parameter you have to put the reference (name) of service that you want to use. ## IExalusConnectionService This service allows us to connect to any controller using cloud connection (in future it will implement local communication too) and call controller APIs. All calls to APIs are asynchronous and can be done concurently. They can be executed out of order depending on the time when given API was called and how fast it can be handled by controller and devices. It is a good practice to wait asynchronously for api call execution. If you want to connect to controller you have to take service from dependency container and call method with controller serial number and PIN. ```typescript import { Api } from 'lavva.exalushome'; import { ExalusConnectionService } from 'lavva.exalushome/build/js/ExalusConnectionService'; import { AuthorizationInfo, IExalusConnectionService } from 'lavva.exalushome/build/js/IExalusConnectionService'; import { ILoggerService } from 'lavva.exalushome/build/js/Services/Logging/ILoggerService'; import { LoggerService } from 'lavva.exalushome/build/js/Services/Logging/LoggerService'; /// get logger service const log = Api.Get<ILoggerService>(LoggerService.ServiceName); /// get exalus connection service const connection = Api.Get<IExalusConnectionService>(ExalusConnectionService.ServiceName); /// subscribe to connection state changed event connection.OnConnectionStateChangedEvent().Subscribe(state => log.Info(`Connection state has changed to: ${state}`)); /// connnect to controller and authorize const result = await connection.ConnectAndAuthorizeAsync(new AuthorizationInfo(serial, pin)); log.Info(`Connection and authorization result: ${result}`); /// check connection and authorization result if (result != ConnectionResult.Connected) { log.Error("Failed to connect to controller!"); return; } log.Info("Connected to controller!"); ``` ## ISessionService This service represents the current app session and has reference to currently logged in user (if any is currently logged in) and can login or logout user. There are two events that you can subsribe to if you want to know when user is logged in or logged out. User can be logged out by controller so it should be handled. ```typescript import { ISessionService, LoginError } from 'lavva.exalushome/build/js/Services/Session/ISessionService'; import { SessionService } from 'lavva.exalushome/build/js/Services/Session/SessionService'; /// get session service const session = Api.Get<ISessionService>(SessionService.ServiceName); session.OnUserLoggedOutEvent().Subscribe(user => log.Info(`User logged out from controller!`)); session.OnUserLoggedInEvent().Subscribe(user => log.Info(`User logged in to controller`)); /// login user const loginResult = await session.UserLogInAsync("installator@installator", "QT54K96X3P9299"); /// check login result if (loginResult instanceof User) { log.Info(SessionService, `logged in as ${loginResult.Name} ${loginResult.Surname} email: ${loginResult.Email}`); } else log.Error(SessionService, `Failed to login, error code: ${loginResult}`); ``` ### IUsersService This service allows us to manage users registered in controller. You can take users list, delete them, create or update. ```typescript /// get users const usersApi = Api.Get<IUsersService>(UsersService.ServiceName); const users = await usersApi.GetUsersAsync(); users.forEach(user => log.Info(`User: ${user.Email}`)); ``` ## IDevicesService This service allows us to manage and control devices. Getting DevicesService: ```typescript const devicesApi = Api.Get<IDevicesService>(DevicesService.ServiceName); await devicesApi.WaitForSynchronizationAsync(); ``` Getting devices list: ```typescript const devices = await devicesApi.GetDevicesAsync(); devices.forEach(device => { log.Info(`[DEVICE] Name: ${device.Name} Guid: ${device.Guid}`); device.AvailableTaskTypes.forEach(task => log.Info(` Task type: ${task.InterfaceType} enum type: ${task.Type}`)); device.AvailableResponseTypes.forEach(resp => log.Info(` Response type: ${resp.InterfaceType} enum type: ${resp.Type}`)); device.Channels.forEach(ch => { log.Info(` Channel: ${ch.Name} num: ${ch.Number}`); ch.AvailableTaskTypes.forEach(task => log.Info(` Task type: ${task.InterfaceType} enum type: ${task.Type}`)); ch.AvailableResponseTypes.forEach(resp => log.Info(` Response type: ${resp.InterfaceType} enum type: ${resp.Type}`)); }); }); ``` Subscribing to device state changes: ```typescript let onStateChange = (stateChange: IDeviceState<any>) => log.Info(`[DEVICE][STATE CHANGED] changed DeviceGuid: ${device.Guid} Name: ${device.Name} \nstate: ${stateChange.TypeAsEnum}"`); device.OnDeviceStateChangedEvent().Subscribe(onStateChange); ``` Canceling subscription to device state changes: ```typescript device.OnDeviceStateChangedEvent().Unsubscribe(onStateChange); ``` Monitoring tasks execution on devices: ```typescript devicesApi.OnDevicesTasksExecutionChangeEvent().Subscribe(tasks => { tasks.forEach(task => log.Info(`Executing tasks on device: ${task.DeviceGuid} channel: ${task.Channel} status: ${task.Status}`)); }); ``` Searching for devices: ```typescript devicesApi.OnDeviceFoundEvent().Subscribe(device => log.Info(`Found new device ${device.Name}`)); await devicesApi.FindDevicesAsync(); const foundDevices = await devicesApi.GetFoundDevicesAsync(); ``` Registering found devices: ```typescript foundDevices.forEach(async device => { log.Warning(`Found device: ${device.Name}`); switch (await devicesApi.RegisterDeviceAsync(device)) { case DeviceTaskExecutionResult.Executed: log.Warning(`Device ${device.Name} has been successfully registered!`); break; case DeviceTaskExecutionResult.Failed: log.Error(`Failed to register device: ${device.Name}`); break; case DeviceTaskExecutionResult.ControllerResponseTimeout: log.Error(`Controller response timeout, unknown status of device: ${device.Name}`); break; case DeviceTaskExecutionResult.DeviceResponseTimeout: log.Error(`Device response timeout, unknown status of device: ${device.Name}`); break; } }); ``` Turning on light on first channel on first device that can be turned on: ```typescript (await devicesApi.GetDevicesAsync()).first(device => device.Channels.any(channel => channel.AvailableTaskTypes.any(a => a.Type === DeviceTaskType.TurnOn && channel.Number === 1))) .Channels.first(channel => channel.Number === 1) .ExecuteTaskAsync(new TurnOn()); /// alternatively you can use let task = new TurnOn(); task.Channel = 1; devicesApi.ExecuteDeviceTaskAsync(device, task); ``` Turning off light on first channel on first device that can be turned on: ```typescript (await devicesApi.GetDevicesAsync()).first(device => device.Channels.any(channel => channel.AvailableTaskTypes.any(a => a.Type === DeviceTaskType.TurnOff && channel.Number === 1))) .Channels.first(channel => channel.Number === 1) .ExecuteTaskAsync(new TurnOff()); ``` Turning on all channels on devices that can be turned on: ```typescript (await devicesApi.GetDevicesAsync()).forEach(device => { device.Channels.forEach(async channel => { if (channel.AvailableTaskTypes.any(a => a.Type === DeviceTaskType.TurnOn)) { let task = new TurnOn(); task.Channel = channel.Number; tasks.push([device, task]); } }); }); let result = await devicesApi.ExecuteDevicesTasksAsync(tasks); result.forEach(response => { switch (response.Result) { case DeviceTaskExecutionResult.Executed: log.Info(`Turned on device: ${response.Device?.Name} on channel: ${response.Task?.Channel}`); break; case DeviceTaskExecutionResult.DeviceResponseTimeout: log.Warning(`Failed to turn on device: ${response.Device?.Name} on channel: ${response.Task?.Channel}, device response timeout occurred`); break; case DeviceTaskExecutionResult.ControllerResponseTimeout: log.Warning(`Unknown device state: ${response.Device?.Name} on channel: ${response.Task?.Channel}, controller response timeout occurred`); break; case DeviceTaskExecutionResult.Failed: log.Error(`Error uccured when tried to turn on device: ${response.Device?.Name} on channel: ${response.Task?.Channel}`); break; } }); ``` Enabling fast devices states synchronization: ```typescript await devices.EnableFastStatesSyncAsync(); ``` Disabling fast devices states synchronization: ```typescript await devices.DisableFastStatesSyncAsync(); ``` Checking if fast states synchronization is enabled: ```await devices.IsFastStatesSyncEnabledAsync();``` ## IControllerConfigurationService This service allows us to manage, control and monitor controller configuration. Getting IControllerConfigurationService: ```typescript const controllerConfigurationApi = Api.Get<IControllerConfigurationService>(ControllerConfigurationService.ServiceName); ``` Monitoring controller configuration changes: ```typescript controllerConfigurationApi.OnConfigurationTimeCheckedEvent().Subscribe(date => log.Warning(`Controller configuration time changed: ${date}`)); controllerConfigurationApi.OnEnteredConfigurationEvent().Subscribe(() => log.Warning(`Controller entered configuration mode`)); controllerConfigurationApi.OnExitedConfigurationEvent().Subscribe(() => log.Warning(`Controller exited configuration mode`)); ``` Entering configuration mode: ```typescript await controllerConfigurationApi.EnterConfigurationModeAsync(); ``` Exiting configuration mode: ```typescript await controllerConfigurationApi.ExitConfigurationModeAsync(); ``` Check if configuration has changed in comparison to the last known konfiguration by this app instance: ```typescript if (await controllerConfigurationApi.DidCofigurationChangeAsync()) log.Warning(`Controller configuration has changed! ${await controllerConfigurationApi.GetLastConfigurationChangeTimeAsync()}`);\ else log.Debug("Controller configuration did not change!"); ``` ## IChannelsGroupsService This service allows us to control devices channels groups. Getting IChannelsGroupsService: ```typescript const groupsApi = Api.Get<IChannelsGroupsService>(ChannelsGroupsService.ServiceName); await groupsApi.WaitForSynchronizationAsync(); // good to use one time after user logs in. ``` Getting groups: ```typescript let groups = await groupsApi.GetGroupsAsync(); groups.forEach(group => log.Info(`Group: ${group.Name} guid: ${group.Guid}`)); ``` Removing group: ```typescript await groupsApi.RemoveGroupAsync(groups.first(a => a.Name === "TEST")); ``` Creating new group: ```typescript let gr = new ChannelsGroup(); gr.Name = "TEST"; await groupsApi.AddNewGroupAsync(gr); ``` Adding device channel to group: ```typescript await groupsApi.AddDeviceChannelToGroupAsync((await devicesApi.GetDevicesAsync()).first().Channels.first(), gr); ``` ## IRemoteStorageService This service allows application to store data (whatever it want's to store) in similar way like Local Storage in JavaScript but this data is not stored locally in browser but it is stored on Exalus Home controller. It can be then synchronized between app instances and retrieved or updated by app. It allows to store data in context of given logged in user or as global database that can be retrieved and modified by anyone. If it is stored in context of user then only the user that created given database can access it. You can have similar databases with same name for each user in the system and given user will be able to modify only it's own database. Getting service instance: ```typescript const remoteStorage = Api.Get<IRemoteStorageService>(RemoteStorageService.ServiceName); ``` Saving data globally accessible by every user: ```typescript await remoteStorage.SaveAsync("data_unique_id", true, "some data that can be an object or array too"); ``` Saving data for user that is logged in: ```typescript await remoteStorage.SaveAsync("data_unique_id", false, "some data that can be an object or array too; in context of user"); ``` Retrieving data that has global access: ```typescript await remoteStorage.ReadAsync<boolean>("data_unique_id", true, false) ``` Retrieving data for user that is logged in: ```typescript await remoteStorage.ReadAsync<boolean>("data_unique_id", false, false) ``` Removing global data (it only works on the newest controller software, older version don't have that capability but all will have it after update): ```typescript await remoteStorage.RemoveAsync("data_unique_id", true) ``` Removing user data (it only works on the newest controller software, older version don't have that capability but all will have it after update): ```typescript await remoteStorage.RemoveAsync("data_unique_id", false) ```