diff --git a/ui-ngx/src/app/core/services/public-api.ts b/ui-ngx/src/app/core/services/public-api.ts index 073eefd5e8..f4e770bdb5 100644 --- a/ui-ngx/src/app/core/services/public-api.ts +++ b/ui-ngx/src/app/core/services/public-api.ts @@ -15,6 +15,7 @@ /// export * from './script/node-script-test.service'; +export * from './unit/unit.service'; export * from './broadcast.models'; export * from './broadcast.service'; export * from './dashboard-utils.service'; diff --git a/ui-ngx/src/app/core/services/unit/definitions/all.ts b/ui-ngx/src/app/core/services/unit/definitions/all.ts index 9be86f61e5..7b8d838e45 100644 --- a/ui-ngx/src/app/core/services/unit/definitions/all.ts +++ b/ui-ngx/src/app/core/services/unit/definitions/all.ts @@ -22,6 +22,10 @@ import area, { AreaUnits } from '@core/services/unit/definitions/area'; import charge, { ChargeUnits } from '@core/services/unit/definitions/charge'; import digital, { DigitalUnits } from '@core/services/unit/definitions/digital'; import electricCurrent, { ElectricCurrentUnits } from '@core/services/unit/definitions/electric-current'; +import energy, { EnergyUnits } from '@core/services/unit/definitions/energy'; +import force, { ForceUnits } from '@core/services/unit/definitions/force'; +import frequency, { FrequencyUnits } from '@core/services/unit/definitions/frequency'; +import illuminance,{ IlluminanceUnits } from '@core/services/unit/definitions/illuminance'; import temperature, { TemperatureUnits } from './temperature'; import time, { TimeUnits } from './time'; @@ -33,6 +37,10 @@ export type AllMeasuresUnits = | ChargeUnits | DigitalUnits | ElectricCurrentUnits + | EnergyUnits + | ForceUnits + | FrequencyUnits + | IlluminanceUnits | TemperatureUnits | TimeUnits; @@ -44,6 +52,10 @@ export type AllMeasures = | 'charge' | 'digital' | 'electric-current' + | 'energy' + | 'force' + | 'frequency' + | 'illuminance' | 'temperature' | 'time'; @@ -58,6 +70,10 @@ const allMeasures: Record< charge, digital, 'electric-current': electricCurrent, + energy, + force, + frequency, + illuminance, temperature, time, }; diff --git a/ui-ngx/src/app/core/services/unit/definitions/energy.ts b/ui-ngx/src/app/core/services/unit/definitions/energy.ts new file mode 100644 index 0000000000..1ec341f565 --- /dev/null +++ b/ui-ngx/src/app/core/services/unit/definitions/energy.ts @@ -0,0 +1,145 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models'; + +export type EnergyUnits = EnergyMetricUnits | EnergyImperialUnits; + +export type EnergyMetricUnits = + | 'Wm' + | 'Wh' + | 'mWh' + | 'kWh' + | 'MWh' + | 'GWh' + | 'μJ' + | 'mJ' + | 'J' + | 'kJ' + | 'MJ' + | 'GJ' + | 'eV'; + +export type EnergyImperialUnits = 'kcal' | 'cal' | 'Cal' | 'BTU' | 'ft·lb'; + +const METRIC: TbMeasureUnits = { + ratio: 1 / 4.184, + units: { + Wm: { + name: 'unit.watt-minute', + tags: ['energy', 'watt-minute', 'watt-minutes', 'Wm'], + to_anchor: 60, + }, + Wh: { + name: 'unit.watt-hour', + tags: ['energy', 'watt-hour', 'watt-hours', 'energy usage', 'power consumption', 'energy consumption', 'electricity usage'], + to_anchor: 3600, + }, + mWh: { + name: 'unit.milliwatt-hour', + tags: ['energy', 'milliwatt-hour', 'milliwatt-hours', 'mWh'], + to_anchor: 3.6, + }, + kWh: { + name: 'unit.kilowatt-hour', + tags: ['energy', 'kilowatt-hour', 'kilowatt-hours', 'energy usage', 'power consumption', 'energy consumption', 'electricity usage'], + to_anchor: 3600000, + }, + MWh: { + name: 'unit.megawatt-hour', + tags: ['energy', 'megawatt-hour', 'megawatt-hours', 'MWh'], + to_anchor: 3600000000, + }, + GWh: { + name: 'unit.gigawatt-hour', + tags: ['energy', 'gigawatt-hour', 'gigawatt-hours', 'GWh'], + to_anchor: 3600000000000, + }, + μJ: { + name: 'unit.microjoule', + tags: ['energy', 'microjoule', 'microjoules', 'μJ'], + to_anchor: 0.000001, + }, + mJ: { + name: 'unit.millijoule', + tags: ['energy', 'millijoule', 'millijoules', 'mJ'], + to_anchor: 0.001, + }, + J: { + name: 'unit.joule', + tags: ['joule', 'joules', 'energy', 'work done', 'heat', 'electricity', 'mechanical work'], + to_anchor: 1, + }, + kJ: { + name: 'unit.kilojoule', + tags: ['energy', 'kilojoule', 'kilojoules', 'kJ'], + to_anchor: 1000, + }, + MJ: { + name: 'unit.megajoule', + tags: ['energy', 'megajoule', 'megajoules', 'MJ'], + to_anchor: 1000000, + }, + GJ: { + name: 'unit.gigajoule', + tags: ['energy', 'gigajoule', 'gigajoules', 'GJ'], + to_anchor: 1000000000, + }, + eV: { + name: 'unit.electron-volts', + tags: ['energy', 'subatomic particles', 'radiation'], + to_anchor: 1.602176634e-19, + }, + }, +}; + +const IMPERIAL: TbMeasureUnits = { + ratio: 4.184, + units: { + cal: { + name: 'unit.small-calorie', + tags: ['energy', 'small calorie', 'calories', 'cal'], + to_anchor: 1, + }, + Cal: { + name: 'unit.calorie', + tags: ['energy', 'food energy', 'Calorie', 'Calories', 'Cal'], + to_anchor: 1000, + }, + kcal: { + name: 'unit.kilocalorie', + tags: ['energy', 'small calorie', 'kilocalories', 'kcal'], + to_anchor: 1000, + }, + BTU: { + name: 'british-thermal-unit', + tags: ['energy', 'heat', 'work done', 'british thermal unit', 'british thermal units', 'BTU'], + to_anchor: 252.164401, + }, + 'ft·lb': { + name: 'unit.foot-pound', + tags: ['energy', 'foot-pound', 'foot-pounds', 'ft·lb', 'ft⋅lbf'], + to_anchor: 0.32404875717017, + }, + }, +}; + +const measure: TbMeasure = { + METRIC, + IMPERIAL +}; + +export default measure; diff --git a/ui-ngx/src/app/core/services/unit/definitions/force.ts b/ui-ngx/src/app/core/services/unit/definitions/force.ts new file mode 100644 index 0000000000..46ee193829 --- /dev/null +++ b/ui-ngx/src/app/core/services/unit/definitions/force.ts @@ -0,0 +1,81 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models'; + +export type ForceUnits = ForceMetricUnits | ForceImperialUnits; + +export type ForceMetricUnits = 'N' | 'kN' | 'dyn'; +export type ForceImperialUnits = 'lbf' | 'kgf' | 'klbf' | 'pdl' | 'kip'; + +const METRIC: TbMeasureUnits = { + ratio: 0.224809, + units: { + N: { + name: 'unit.newton', + tags: ['force', 'pressure', 'newton', 'newtons', 'N', 'push', 'pull', 'weight', 'gravity', 'N'], + to_anchor: 1, + }, + kN: { + name: 'unit.kilonewton', + tags: ['force', 'kN'], + to_anchor: 1000, + }, + dyn: { + name: 'unit.dyne', + tags: ['force', 'dyn'], + to_anchor: 0.00001, + }, + }, +}; + +const IMPERIAL: TbMeasureUnits = { + ratio: 4.44822, + units: { + lbf: { + name: 'unit.pound-force', + tags: ['force', 'lbf'], + to_anchor: 1, + }, + kgf: { + name: 'unit.kilogram-force', + tags: ['force', 'kgf'], + to_anchor: 2.20462, + }, + klbf: { + name: 'unit.kilopound-force', + tags: ['force', 'klbf'], + to_anchor: 1000, + }, + pdl: { + name: 'unit.poundal', + tags: ['force', 'pdl'], + to_anchor: 0.031081, + }, + kip: { + name: 'unit.kip', + tags: ['force', 'kip'], + to_anchor: 1000, + }, + }, +}; + +const measure: TbMeasure = { + METRIC, + IMPERIAL +}; + +export default measure; diff --git a/ui-ngx/src/app/core/services/unit/definitions/frequency.ts b/ui-ngx/src/app/core/services/unit/definitions/frequency.ts new file mode 100644 index 0000000000..ecff651b78 --- /dev/null +++ b/ui-ngx/src/app/core/services/unit/definitions/frequency.ts @@ -0,0 +1,76 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models'; + +export type FrequencyUnits = FrequencyMetricUnits; +export type FrequencyMetricUnits = 'mHz' | 'Hz' | 'kHz' | 'MHz' | 'GHz' | 'THz' | 'rpm' | 'deg/s' | 'rad/s'; + +const METRIC: TbMeasureUnits = { + units: { + mHz: { + name: 'unit.millihertz', + tags: ['frequency', 'cycles per second', 'millihertz', 'mHz'], + to_anchor: 1 / 1000, + }, + Hz: { + name: 'unit.hertz', + tags: ['frequency', 'cycles per second', 'hertz', 'Hz'], + to_anchor: 1, + }, + kHz: { + name: 'unit.kilohertz', + tags: ['frequency', 'cycles per second', 'kilohertz', 'kHz'], + to_anchor: 1000, + }, + MHz: { + name: 'unit.megahertz', + tags: ['frequency', 'cycles per second', 'megahertz', 'MHz'], + to_anchor: 1000 * 1000, + }, + GHz: { + name: 'unit.gigahertz', + tags: ['frequency', 'cycles per second', 'gigahertz', 'GHz'], + to_anchor: 1000 * 1000 * 1000, + }, + THz: { + name: 'unit.terahertz', + tags: ['frequency', 'terahertz', 'THz'], + to_anchor: 1000 * 1000 * 1000 * 1000, + }, + rpm: { + name: 'unit.rotation-per-minute', + tags: ['frequency', 'rotation per minute', 'rotations per minute', 'rpm', 'angular velocity'], + to_anchor: 1 / 60, + }, + 'deg/s': { + name: 'unit.deg-per-second', + tags: ['angular velocity', 'degrees per second', 'deg/s'], + to_anchor: 1 / 360, // 1 deg/s = 1/360 Hz + }, + 'rad/s': { + name: 'unit.radian-per-second', + tags: ['angular velocity', 'rotation speed', 'rad/s'], + to_anchor: 1 / (Math.PI * 2), + }, + }, +}; + +const measure: TbMeasure = { + METRIC, +}; + +export default measure; diff --git a/ui-ngx/src/app/core/services/unit/definitions/illuminance.ts b/ui-ngx/src/app/core/services/unit/definitions/illuminance.ts new file mode 100644 index 0000000000..6c1ae4d43d --- /dev/null +++ b/ui-ngx/src/app/core/services/unit/definitions/illuminance.ts @@ -0,0 +1,61 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models'; + +export type IlluminanceUnits = IlluminanceMetricUnits | IlluminanceImperialUnits; + +export type IlluminanceMetricUnits = 'lx' | 'cd/m²' | 'lm/m²'; +export type IlluminanceImperialUnits = 'fc'; + +const METRIC: TbMeasureUnits = { + ratio: 1 / 10.76391, + units: { + lx: { + name: 'unit.lux', + tags: ['illumination', 'light level on a surface', 'illuminance', 'Lux', 'lx'], + to_anchor: 1, + }, + 'cd/m²': { + name: 'unit.candela-per-square-meter', + tags: ['brightness', 'light level', 'Luminance', 'Candela per square meter', 'cd/m²'], + to_anchor: 1, + }, + 'lm/m²': { + name: 'unit.lumen-per-square-meter', + tags: ['illumination', 'light level', 'lumen per square meter', 'lm/m²'], + to_anchor: 1, + }, + }, +}; + +const IMPERIAL: TbMeasureUnits = { + ratio: 10.76391, + units: { + 'fc': { + name: 'unit.foot-candle', + tags: ['illuminance', 'light level', 'foot-candle', 'fc'], + to_anchor: 1, + }, + }, +}; + +const measure: TbMeasure = { + METRIC, + IMPERIAL, +}; + +export default measure; diff --git a/ui-ngx/src/app/modules/home/models/services.map.ts b/ui-ngx/src/app/modules/home/models/services.map.ts index e4bbc15936..481e070b90 100644 --- a/ui-ngx/src/app/modules/home/models/services.map.ts +++ b/ui-ngx/src/app/modules/home/models/services.map.ts @@ -51,6 +51,7 @@ import { TenantProfileService } from '@core/http/tenant-profile.service'; import { UiSettingsService } from '@core/http/ui-settings.service'; import { UsageInfoService } from '@core/http/usage-info.service'; import { EventService } from '@core/http/event.service'; +import { UnitService } from '@core/services/unit/unit.service'; import { AuditLogService } from '@core/http/audit-log.service'; export const ServicesMap = new Map>( @@ -91,6 +92,7 @@ export const ServicesMap = new Map>( ['usageInfoService', UsageInfoService], ['notificationService', NotificationService], ['eventService', EventService], + ['unitService', UnitService], ['auditLogService', AuditLogService] ] ); diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 68c160a9ca..a40481ea51 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5872,6 +5872,10 @@ "charge": "Charge", "digital": "Digital", "electric-current": "Electric current", + "energy": "Energy", + "force": "Force", + "frequency": "Frequency", + "illuminance": "Illuminance", "temperature": "Temperature", "time": "Time" }, @@ -5984,7 +5988,11 @@ "megajoule": "Megajoule", "gigajoule": "Gigajoule", "watt-hour": "Watt-hour", + "watt-minute": "Watt-minute", "kilowatt-hour": "Kilowatt-hour", + "milliwatt-hour": "Milliwatt-hour", + "megawatt-hour": "Megawatt-hour", + "gigawatt-hour": "Gigawatt-hour", "electron-volts": "Electron volts", "joules-per-coulomb": "Joules per Coulomb", "british-thermal-unit": "British Thermal Units", @@ -6087,10 +6095,12 @@ "kilohm": "Kilohm", "megohm": "Megohm", "gigohm": "Gigohm", + "millihertz": "Millihertz", "hertz": "Hertz", "kilohertz": "Kilohertz", "megahertz": "Megahertz", "gigahertz": "Gigahertz", + "terahertz": "Terahertz", "rpm": "Revolutions Per Minute", "candela-per-square-meter": "Candela per square meter", "candela": "Candela", @@ -6290,6 +6300,7 @@ "radian-per-second-squared": "Radian per second squared", "revolutions-per-minute-per-second": "Angular acceleration", "deg-per-second": "deg/s", + "rotation-per-minute": "Rotation per minute", "degrees-brix": "Degrees Brix", "katal": "Katal", "katal-per-cubic-metre": "Katal per Cubic Metre"