myio-js-library
v0.1.219
Published
A clean, standalone JS SDK for MYIO projects
Readme
myio-js-library
A clean, standalone JavaScript SDK for MYIO projects. Works in Node.js (>=18) and modern browsers. Distributed as ESM, CJS, and UMD (with a pre-minified build for CDN usage).
🎨 Interactive Showcase
Explore all library features with interactive demos and live examples:
The showcase includes:
- 📊 Format Utilities - Energy, water, percentages, and numbers
- 📅 Date Utilities - Date formatting, intervals, timezone handling
- 🚦 Device Status - Status types, ranges, and calculations
- 🎴 Card Components - Head Office device cards with full interactivity
- 🪟 Modal Components - Settings, filters, and reports
- 🔧 MYIO Components - Selection store, authentication, CSV export
🚀 Features
- 🔑 Core codecs — e.g.,
decodePayloadBase64Xor. - 🌐 HTTP wrapper — with retries, timeout, and backoff.
- 🏷️ Namespace utilities — add prefixes/suffixes to object keys.
- 📱 Device detection — context-aware device type identification.
- 🧩 String utilities — normalization helpers.
- 🔢 Number utilities — safe fixed formatting, percentages.
- ⚡ Energy formatting — Brazilian locale energy unit formatting (kWh, MWh, GWh).
- 📅 Date utilities — date formatting, interval detection, São Paulo timezone handling.
- 📊 CSV export — data export to CSV format with proper escaping (returns strings, no DOM manipulation).
- 🏷️ Classification — energy entity classification utilities.
- 🔍 Data access — nested object value retrieval with datakey paths.
- 🔌 Device status — comprehensive status calculation and management with
calculateDeviceStatus. - 🎯 Goals Panel — consumption goals setup with annual/monthly targets, versioning, and ThingsBoard integration.
- ⚡ Dual module support — ESM and CJS.
- 🌍 Browser-ready — UMD global + CDN link.
📦 Installation
npm install myio-js-library
# or
yarn add myio-js-library
# or
pnpm add myio-js-library🛠 Usage
Node.js (ESM)
import {
decodePayload,
decodePayloadBase64Xor,
fetchWithRetry,
http,
addNamespace,
detectDeviceType,
strings,
numbers,
formatEnergy,
formatWaterVolumeM3,
formatDateToYMD,
exportToCSV,
classifyWaterLabel,
getValueByDatakey,
calculateDeviceStatus,
DeviceStatusType,
openGoalsPanel
} from 'myio-js-library';
// Decode with string key
const text = decodePayload('AwAVBwo=', 'key'); // "hello"
console.log(text);
// HTTP request with retries
const response = await fetchWithRetry('https://api.example.com/data', {
retries: 3,
timeout: 5000
});
// Add namespace to object keys
const data = { temperature: 25, humidity: 60 };
const namespaced = addNamespace(data, 'sensor1');
// { "temperature (sensor1)": 25, "humidity (sensor1)": 60 }
// Detect device type from context
const deviceType = detectDeviceType('building', 'floor2-room101');
console.log(deviceType); // "room" or "unknown"
// Calculate device status
const status = calculateDeviceStatus({
connectionStatus: "online",
lastConsumptionValue: 500,
limitOfPowerOnStandByWatts: 100,
limitOfPowerOnAlertWatts: 1000,
limitOfPowerOnFailureWatts: 2000
});
console.log(status); // "power_on"
// Open goals panel for consumption management
const panel = openGoalsPanel({
customerId: 'customer-uuid',
token: 'jwt-token',
shoppingList: [
{ value: 'shop-1', name: 'Shopping Centro' }
],
onSave: (data) => console.log('Goals saved:', data)
});Node.js (CJS)
const {
decodePayload,
fetchWithRetry,
addNamespace,
detectDeviceType,
strings,
numbers
} = require('myio-js-library');Browser (CDN/UMD)
<script src="https://unpkg.com/[email protected]/dist/myio-js-library.umd.min.js"></script>
<script>
// Decode payload
const text = MyIOLibrary.decodePayload('AwAVBwo=', 'key');
console.log(text); // "hello"
// Add namespace to data
const data = { temperature: 25, humidity: 60 };
const namespaced = MyIOLibrary.addNamespace(data, 'sensor1');
console.log(namespaced); // { "temperature (sensor1)": 25, "humidity (sensor1)": 60 }
// Detect device type
const deviceType = MyIOLibrary.detectDeviceType('building', 'floor2-room101');
console.log(deviceType); // "room"
</script>📚 API
Codec Functions
decodePayload(encoded: string, key: string | number | null | undefined): string
Advanced base64 XOR decoder with flexible key support:
- String key: Repeats the key over the bytes (e.g., "abc" -> "abcabcabc...")
- Number key: Applies single byte (0-255) to all bytes
- Empty/null/undefined key: No XOR applied (plain base64 decode)
import { decodePayload } from 'myio-js-library';
// String key (repeating)
const result1 = decodePayload('AwAVBwo=', 'key'); // "hello"
// Number key (single byte)
const result2 = decodePayload('SGVsbG8=', 73); // XOR with 73
// No key (plain decode)
const result3 = decodePayload('aGVsbG8=', ''); // "hello"decodePayloadBase64Xor(encoded: string, xorKey?: number): string
Legacy compatibility function for single-byte XOR (defaults to 73).
import { decodePayloadBase64Xor } from 'myio-js-library';
const result = decodePayloadBase64Xor('SGVsbG8=', 73);HTTP Functions
fetchWithRetry(url: string, options?: object): Promise<Response>
Enhanced fetch wrapper with retry logic, timeout, and exponential backoff.
Options:
retries?: number- Number of retry attempts (default: 0)retryDelay?: number- Base delay between retries in ms (default: 100)timeout?: number- Request timeout in ms (default: 10000)retryCondition?: (error, response) => boolean- Custom retry logic- All standard
fetchoptions (method, headers, body, signal, etc.)
import { fetchWithRetry } from 'myio-js-library';
const response = await fetchWithRetry('https://api.example.com/data', {
retries: 3,
retryDelay: 200,
timeout: 5000,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: 'example' })
});http(url: string, options?: object): Promise<Response>
Alias for fetchWithRetry.
Namespace Utilities
addNamespace(payload: object, namespace?: string): object
Adds a namespace suffix to all keys in an object. Useful for prefixing data from different sources or sensors.
Parameters:
payload: object- The object whose keys will be namespaced (must be a plain object, not array)namespace?: string- The namespace to append (optional, defaults to empty string)
Returns: New object with namespaced keys in format "originalKey (namespace)"
Throws: Error if payload is not a plain object
import { addNamespace } from 'myio-js-library';
// Basic usage
const data = { temperature: 25, humidity: 60 };
const result = addNamespace(data, 'sensor1');
// { "temperature (sensor1)": 25, "humidity (sensor1)": 60 }
// Empty namespace (no suffix added)
const result2 = addNamespace(data, '');
// { "temperature": 25, "humidity": 60 }
// Whitespace handling
const result3 = addNamespace(data, ' room-101 ');
// { "temperature (room-101)": 25, "humidity (room-101)": 60 }Device Detection Utilities
detectDeviceType(context: string, deviceId: string): string
Detects device type based on context and device ID patterns. Uses built-in detection contexts for common environments.
Parameters:
context: string- The context environment ('building', 'mall', etc.)deviceId: string- The device identifier to analyze
Returns: Detected device type or 'unknown' if no pattern matches
Built-in contexts:
- building: Detects rooms, floors, elevators, stairs, parking, entrance, exit
- mall: Detects stores, corridors, escalators, elevators, parking, entrance, exit, food court, restrooms
import { detectDeviceType } from 'myio-js-library';
// Building context
detectDeviceType('building', 'floor2-room101'); // "room"
detectDeviceType('building', 'elevator-A'); // "elevator"
detectDeviceType('building', 'parking-level1'); // "parking"
// Mall context
detectDeviceType('mall', 'store-nike-001'); // "store"
detectDeviceType('mall', 'corridor-main'); // "corridor"
detectDeviceType('mall', 'food-court-area'); // "food_court"
// Unknown patterns
detectDeviceType('building', 'unknown-device'); // "unknown"getAvailableContexts(): string[]
Returns list of all available detection contexts.
import { getAvailableContexts } from 'myio-js-library';
const contexts = getAvailableContexts();
// ['building', 'mall']addDetectionContext(contextName: string, patterns: object): void
Adds a new detection context with custom patterns.
Parameters:
contextName: string- Name of the new contextpatterns: object- Object mapping device types to regex patterns
import { addDetectionContext, detectDeviceType } from 'myio-js-library';
// Add custom hospital context
addDetectionContext('hospital', {
room: /^(room|ward|chamber)-/i,
operating_room: /^(or|surgery|operating)-/i,
emergency: /^(er|emergency|trauma)-/i
});
// Use the new context
detectDeviceType('hospital', 'room-icu-101'); // "room"
detectDeviceType('hospital', 'or-surgery-3'); // "operating_room"String Utilities
strings.normalizeRecipients(val: unknown): string
Normalizes various list formats into a comma-separated string.
Supported inputs:
- Arrays:
['a', 'b', 'c']→"a,b,c" - JSON strings:
'["a", "b", "c"]'→"a,b,c" - Delimited strings:
"a; b, c"→"a,b,c"
import { strings } from 'myio-js-library';
strings.normalizeRecipients(['user1', 'user2']); // "user1,user2"
strings.normalizeRecipients('["a", "b"]'); // "a,b"
strings.normalizeRecipients('a; b, c'); // "a,b,c"Number Utilities
formatNumberReadable(value: unknown, locale?: string, minimumFractionDigits?: number, maximumFractionDigits?: number): string
Formats numbers for Brazilian locale with robust input handling. Safely handles strings, numbers, and other types with sensible defaults.
Parameters:
value: unknown- Value to format (number, string, or any other type)locale?: string- Locale string (default: 'pt-BR')minimumFractionDigits?: number- Minimum decimal places (default: 2)maximumFractionDigits?: number- Maximum decimal places (default: 2)
Features:
- Handles string inputs with comma decimal separators (e.g., "12,34" → 12.34)
- Normalizes -0 to 0
- Returns "-" for null, undefined, NaN, or invalid inputs
- Configurable locale and decimal places
import { formatNumberReadable } from 'myio-js-library';
// Basic usage
formatNumberReadable(1234.56); // "1.234,56"
formatNumberReadable(1000); // "1.000,00"
formatNumberReadable(12.3); // "12,30"
// String inputs (handles comma separators)
formatNumberReadable("1234,56"); // "1.234,56"
formatNumberReadable("12.34"); // "12,34"
// Invalid inputs
formatNumberReadable(null); // "-"
formatNumberReadable(NaN); // "-"
formatNumberReadable("invalid"); // "-"
// Custom locale and precision
formatNumberReadable(1234.56, 'en-US'); // "1,234.56"
formatNumberReadable(1234.56, 'pt-BR', 0, 0); // "1.235"
formatNumberReadable(1234.56, 'pt-BR', 1, 3); // "1.234,560"numbers.fmtPerc(x: number, digits?: number): string
Formats a ratio (0-1) as a percentage string.
import { numbers } from 'myio-js-library';
numbers.fmtPerc(0.1234); // "12.34%"
numbers.fmtPerc(0.1234, 1); // "12.3%"
numbers.fmtPerc(NaN); // "—"numbers.toFixedSafe(x: number, digits?: number): string
Safely formats a number to fixed decimals (returns "—" for invalid numbers).
import { numbers } from 'myio-js-library';
numbers.toFixedSafe(3.14159, 2); // "3.14"
numbers.toFixedSafe(NaN); // "—"
numbers.toFixedSafe(Infinity); // "—"Energy Formatting Utilities
formatEnergy(value: number, unit?: string): string
Formats energy values with Brazilian locale formatting and appropriate units. If no unit is provided, automatically selects the most appropriate unit based on the value magnitude.
Parameters:
value: number- The energy value to formatunit?: string- Optional unit ('kWh', 'MWh', 'GWh'). If not provided, automatically determined based on value
Auto-unit selection:
- Values ≥ 1,000,000: Converts to GWh
- Values ≥ 1,000: Converts to MWh
- Values < 1,000: Uses kWh
import { formatEnergy } from 'myio-js-library';
// With explicit unit
formatEnergy(1234.56, 'kWh'); // "1.234,56 kWh"
formatEnergy(1000, 'MWh'); // "1.000,00 MWh"
// Auto-unit selection
formatEnergy(500); // "500,00 kWh"
formatEnergy(1500); // "1,50 MWh"
formatEnergy(2500000); // "2,50 GWh"
// Invalid values
formatEnergy(null); // "-"
formatEnergy(NaN); // "-"formatAllInSameUnit(values: Array<{value: number, unit: string}>, targetUnit: string): string[]
Converts and formats multiple energy values to the same unit.
import { formatAllInSameUnit } from 'myio-js-library';
const values = [
{ value: 1, unit: 'kWh' },
{ value: 1, unit: 'MWh' },
{ value: 1, unit: 'GWh' }
];
formatAllInSameUnit(values, 'kWh');
// ['1,00 kWh', '1.000,00 kWh', '1.000.000,00 kWh']fmtPerc(value: number): string
Formats percentage values with Brazilian locale formatting.
Note: This function uses Brazilian locale formatting (comma as decimal separator). This is a change from the original behavior which used dot notation. For values less than 0.1%, it returns the formatted percentage rather than "<0,1".
import { fmtPerc } from 'myio-js-library';
fmtPerc(0.1234); // "12,34%"
fmtPerc(0.5); // "50,00%"
fmtPerc(0.001); // "0,10%"
fmtPerc(null); // "-"
fmtPerc(NaN); // "-"Date Utilities
formatDateToYMD(date: Date | number | string): string
Formats dates to YYYY-MM-DD format.
import { formatDateToYMD } from 'myio-js-library';
formatDateToYMD(new Date('2023-12-25')); // "2023-12-25"
formatDateToYMD('2023-01-15T12:00:00Z'); // "2023-01-15"
formatDateToYMD('invalid'); // ""determineInterval(startDate: Date | string | number, endDate: Date | string | number): string
Determines appropriate time interval based on date range.
import { determineInterval } from 'myio-js-library';
const start = new Date('2023-01-01');
const end = new Date('2023-01-05');
determineInterval(start, end); // "day"
const longRange = new Date('2023-06-01');
determineInterval(start, longRange); // "month"getSaoPauloISOString(date: Date | string | number, edge?: 'start' | 'end'): string
Gets ISO string for date at day edge in São Paulo timezone.
import { getSaoPauloISOString } from 'myio-js-library';
const date = new Date('2023-01-01T12:00:00Z');
getSaoPauloISOString(date, 'start'); // ISO string for start of day in SP timezone
getSaoPauloISOString(date, 'end'); // ISO string for end of day in SP timezonegetDateRangeArray(startDate: Date | string | number, endDate: Date | string | number, interval?: 'day' | 'week' | 'month' | 'year'): Date[]
Generates array of dates within specified range.
import { getDateRangeArray } from 'myio-js-library';
const start = new Date('2023-01-01');
const end = new Date('2023-01-03');
const dates = getDateRangeArray(start, end, 'day');
// [Date('2023-01-01'), Date('2023-01-02'), Date('2023-01-03')]CSV Export Utilities
exportToCSV(data: Record<string, any>[], headers: string[], filename?: string): string
Exports data to CSV format with proper escaping.
import { exportToCSV } from 'myio-js-library';
const data = [
{ name: 'John', age: 30, city: 'New York' },
{ name: 'Jane', age: 25, city: 'Los Angeles' }
];
const headers = ['name', 'age', 'city'];
const csv = exportToCSV(data, headers);
// "name,age,city\nJohn,30,New York\nJane,25,Los Angeles"exportToCSVAll(storesData: Record<string, Record<string, any>[]>, headers: string[], filename?: string): string
Exports data for multiple stores/entities to CSV format.
import { exportToCSVAll } from 'myio-js-library';
const storesData = {
'Store A': [
{ product: 'Apple', price: 1.50 },
{ product: 'Banana', price: 0.75 }
],
'Store B': [
{ product: 'Orange', price: 2.00 }
]
};
const headers = ['product', 'price'];
const csv = exportToCSVAll(storesData, headers);
// "Store,product,price\nStore A,Apple,1.5\nStore A,Banana,0.75\nStore B,Orange,2"Classification Utilities
classify(entity: Record<string, any>, criteria: Record<string, any>): {category: string, subcategory?: string, confidence: number}
Classifies energy entities based on their characteristics.
import { classify } from 'myio-js-library';
const entity = { type: 'consumption', powerRating: 5000 };
const criteria = {};
const result = classify(entity, criteria);
// { category: 'energy_consumption', subcategory: 'medium_scale', confidence: 1.0 }Water-Specific Utilities
Water Formatting Functions
formatWaterVolumeM3(value: number, locale?: string): string
Formats water volume in cubic meters (M³) using Brazilian locale formatting.
import { formatWaterVolumeM3 } from 'myio-js-library';
formatWaterVolumeM3(12.345); // "12,35 M³"
formatWaterVolumeM3(1000.5); // "1.000,50 M³"
formatWaterVolumeM3(12.345, 'en-US'); // "12.35 M³"
formatWaterVolumeM3(null); // "-"formatTankHeadFromCm(valueCm: number, locale?: string): string
Formats tank head from centimeters to meters of water column (m.c.a.).
import { formatTankHeadFromCm } from 'myio-js-library';
formatTankHeadFromCm(178); // "1,78 m.c.a."
formatTankHeadFromCm(250); // "2,50 m.c.a."
formatTankHeadFromCm(null); // "-"calcDeltaPercent(prev: number, current: number): {value: number, type: string}
Calculates percentage difference between two values and determines the type of change.
import { calcDeltaPercent } from 'myio-js-library';
calcDeltaPercent(100, 120); // { value: 20, type: "increase" }
calcDeltaPercent(120, 100); // { value: 16.67, type: "decrease" }
calcDeltaPercent(100, 100); // { value: 0, type: "neutral" }
calcDeltaPercent(0, 100); // { value: 100, type: "increase" }formatWaterByGroup(value: number, group: string): string
Formats water group totals in m³. For values ≥ 1000, it returns the value in thousands of m³ with a simplified x 10³ suffix.
Examples
import { formatWaterByGroup } from 'myio-js-library';
formatWaterByGroup(178, "Caixas D'Água"); // "1,78 m.c.a."
formatWaterByGroup(750, "Lojas"); // "750,00 M³"
formatWaterByGroup(2500, "Lojas"); // "2,50 M³ x 10³ "Water Date Utilities
formatDateForInput(date: Date): string
Formats a Date object into a 'YYYY-MM-DD' string for HTML input fields.
import { formatDateForInput } from 'myio-js-library';
formatDateForInput(new Date(2025, 7, 26)); // "2025-08-26"
formatDateForInput(new Date('invalid')); // ""parseInputDateToDate(inputDateStr: string): Date | null
Parses a 'YYYY-MM-DD' string into a Date object at midnight local time.
import { parseInputDateToDate } from 'myio-js-library';
parseInputDateToDate('2025-08-26'); // Date object at 2025-08-26 00:00:00
parseInputDateToDate('invalid'); // nulltimeWindowFromInputYMD(startYmd: string, endYmd: string, tzOffset?: string): {startTs: number, endTs: number}
Creates a time window from two input date strings with timezone offset.
import { timeWindowFromInputYMD } from 'myio-js-library';
timeWindowFromInputYMD('2025-08-01', '2025-08-26', '-03:00');
// { startTs: 1722470400000, endTs: 1724630399999 }getSaoPauloISOStringFixed(dateStr: string, endOfDay?: boolean): string
Gets São Paulo ISO string with fixed offset.
import { getSaoPauloISOStringFixed } from 'myio-js-library';
getSaoPauloISOStringFixed('2025-08-26'); // "2025-08-26T00:00:00.000-03:00"
getSaoPauloISOStringFixed('2025-08-26', true); // "2025-08-26T23:59:59.999-03:00"averageByDay(data: TimedValue[]): Array<{day: string, average: number}>
Calculates the average value per day from time-series data.
import { averageByDay } from 'myio-js-library';
const data = [
{ ts: new Date('2025-08-26T10:00:00'), value: 100 },
{ ts: new Date('2025-08-26T14:00:00'), value: 200 },
{ ts: new Date('2025-08-27T10:00:00'), value: 150 }
];
averageByDay(data);
// [
// { day: '2025-08-26', average: 150 },
// { day: '2025-08-27', average: 150 }
// ]Water CSV Utilities
buildWaterReportCSV(rows: WaterRow[], meta: object): string
Builds a CSV string for water consumption reports.
import { buildWaterReportCSV } from 'myio-js-library';
const rows = [
{
formattedDate: '26/08/2025',
day: 'Segunda-feira',
avgConsumption: '12,50',
minDemand: '10,00',
maxDemand: '15,00',
totalConsumption: '300,00'
}
];
const meta = {
issueDate: '26/08/2025 - 23:19',
name: 'Loja A',
identifier: 'SCP001'
};
buildWaterReportCSV(rows, meta);
// "DATA EMISSÃO;26/08/2025 - 23:19\nTotal;300.00\nLoja:;Loja A;SCP001\n..."buildWaterStoresCSV(rows: StoreRow[], meta: object): string
Builds a CSV string for all stores water consumption report.
import { buildWaterStoresCSV } from 'myio-js-library';
const rows = [
{
entityLabel: 'Loja A',
deviceId: 'DEV001',
consumptionM3: 150.5
}
];
const meta = {
issueDate: '26/08/2025 - 23:19'
};
buildWaterStoresCSV(rows, meta);
// "DATA EMISSÃO;26/08/2025 - 23:19\nTotal;150.50\nLoja;Identificador;Consumo\n..."toCSV(rows: (string|number)[][], delimiter?: string): string
Basic CSV generation function that converts 2D array to CSV string.
import { toCSV } from 'myio-js-library';
const rows = [
['Header1', 'Header2'],
['Value1', 'Value2'],
['Value3', 'Value4']
];
toCSV(rows); // "Header1;Header2\nValue1;Value2\nValue3;Value4"
toCSV(rows, ','); // "Header1,Header2\nValue1,Value2\nValue3,Value4"Water Classification Utilities
classifyWaterLabel(label: string): string
Classifies water device labels into predefined categories.
import { classifyWaterLabel } from 'myio-js-library';
classifyWaterLabel('Caixa Superior'); // "Caixas D'Água"
classifyWaterLabel('Administração'); // "Área Comum"
classifyWaterLabel('Loja 101'); // "Lojas"
classifyWaterLabel(''); // "Lojas" (default)classifyWaterLabels(labels: string[]): object
Classifies multiple labels and returns a summary.
import { classifyWaterLabels } from 'myio-js-library';
const labels = ['Caixa Superior', 'Loja 101', 'Administração'];
classifyWaterLabels(labels);
// {
// "Caixas D'Água": 1,
// "Lojas": 1,
// "Área Comum": 1,
// total: 3
// }getWaterCategories(): string[]
Gets all possible water classification categories.
import { getWaterCategories } from 'myio-js-library';
getWaterCategories(); // ["Caixas D'Água", "Lojas", "Área Comum"]isWaterCategory(label: string, category: string): boolean
Checks if a label belongs to a specific category.
import { isWaterCategory } from 'myio-js-library';
isWaterCategory('Caixa Superior', "Caixas D'Água"); // true
isWaterCategory('Loja 101', "Caixas D'Água"); // falseDevice Status Utilities
The library provides comprehensive device status management utilities for IoT applications, enabling centralized status calculation, validation, and visual mapping.
calculateDeviceStatus(params: object): string
Calculates device operational status based on connection state and power consumption metrics. This is the primary function for determining device status across MYIO applications.
Parameters:
connectionStatus: "waiting" | "offline" | "online"- Device connection state (required)lastConsumptionValue: number | null- Power consumption in watts (required)limitOfPowerOnStandByWatts: number- Upper threshold for standby mode in watts (required)limitOfPowerOnAlertWatts: number- Upper threshold for normal operation (power_on) in watts (required)limitOfPowerOnFailureWatts: number- Upper threshold for warning mode in watts (required)
Returns: Device status string from DeviceStatusType enum:
"not_installed"- Device waiting for installation"no_info"- Device offline, no information available"power_on"- Device in normal operation"standby"- Low power consumption mode (0 to standby limit)"warning"- Elevated consumption (alert limit to failure limit)"failure"- Critical consumption (above failure limit)"maintenance"- Invalid state requiring attention
Decision Logic:
waiting → NOT_INSTALLED
offline → NO_INFO
online + no data → POWER_ON
online + (0 ≤ consumption ≤ standbyLimit) → STANDBY
online + (standbyLimit < consumption ≤ alertLimit) → POWER_ON
online + (alertLimit < consumption ≤ failureLimit) → WARNING
online + (consumption > failureLimit) → FAILURE
invalid → MAINTENANCEUsage Example:
import { calculateDeviceStatus, DeviceStatusType } from 'myio-js-library';
// Air Conditioner - Normal operation
const acStatus = calculateDeviceStatus({
connectionStatus: "online",
lastConsumptionValue: 2500, // 2.5 kW
limitOfPowerOnStandByWatts: 500, // 500W standby
limitOfPowerOnAlertWatts: 3000, // 3kW alert
limitOfPowerOnFailureWatts: 5000 // 5kW failure
});
console.log(acStatus); // "power_on"
// Elevator - Standby
const elevatorStatus = calculateDeviceStatus({
connectionStatus: "online",
lastConsumptionValue: 80, // 80W
limitOfPowerOnStandByWatts: 150,
limitOfPowerOnAlertWatts: 800,
limitOfPowerOnFailureWatts: 1200
});
console.log(elevatorStatus); // "standby"
// Offline device
const offlineStatus = calculateDeviceStatus({
connectionStatus: "offline",
lastConsumptionValue: null,
limitOfPowerOnStandByWatts: 100,
limitOfPowerOnAlertWatts: 1000,
limitOfPowerOnFailureWatts: 2000
});
console.log(offlineStatus); // "no_info"Interactive Demo: See demos/calculate-device-status.html for an interactive demonstration with multiple scenarios.
Complete Documentation: See docs/calculateDeviceStatus.md for comprehensive documentation with advanced examples.
Device Status Constants and Helper Functions
DeviceStatusType - Status Type Enum
import { DeviceStatusType } from 'myio-js-library';
DeviceStatusType.POWER_ON // "power_on"
DeviceStatusType.STANDBY // "standby"
DeviceStatusType.POWER_OFF // "power_off"
DeviceStatusType.WARNING // "warning"
DeviceStatusType.FAILURE // "failure"
DeviceStatusType.MAINTENANCE // "maintenance"
DeviceStatusType.NO_INFO // "no_info"
DeviceStatusType.NOT_INSTALLED // "not_installed"deviceStatusIcons - Icon Mapping
import { deviceStatusIcons, getDeviceStatusIcon } from 'myio-js-library';
// Icon map
deviceStatusIcons[DeviceStatusType.POWER_ON] // "⚡"
deviceStatusIcons[DeviceStatusType.STANDBY] // "🔌"
deviceStatusIcons[DeviceStatusType.WARNING] // "⚠️"
deviceStatusIcons[DeviceStatusType.FAILURE] // "🚨"
deviceStatusIcons[DeviceStatusType.NO_INFO] // "❓️"
deviceStatusIcons[DeviceStatusType.NOT_INSTALLED] // "📦"
// Helper function
getDeviceStatusIcon("warning"); // "⚠️"
getDeviceStatusIcon("failure"); // "🚨"getDeviceStatusInfo(deviceStatus: string): object
Gets comprehensive status information including derived properties.
import { getDeviceStatusInfo } from 'myio-js-library';
const info = getDeviceStatusInfo("warning");
console.log(info);
// {
// deviceStatus: "warning",
// connectionStatus: "connected",
// cardStatus: "alert",
// deviceIcon: "⚠️",
// connectionIcon: "🟢",
// shouldFlash: true,
// isOffline: false,
// isValid: true
// }Status Mapping Functions
import {
mapDeviceStatusToCardStatus,
mapDeviceToConnectionStatus,
shouldFlashIcon,
isDeviceOffline
} from 'myio-js-library';
// Map to simplified card status
mapDeviceStatusToCardStatus("warning"); // "alert"
mapDeviceStatusToCardStatus("power_on"); // "ok"
mapDeviceStatusToCardStatus("failure"); // "fail"
// Map to connection status
mapDeviceToConnectionStatus("no_info"); // "offline"
mapDeviceToConnectionStatus("power_on"); // "connected"
// Visual indicators
shouldFlashIcon("failure"); // true (requires attention)
shouldFlashIcon("warning"); // true (requires attention)
shouldFlashIcon("power_on"); // false (normal operation)
isDeviceOffline("no_info"); // true
isDeviceOffline("standby"); // falseValidation Functions
import {
isValidDeviceStatus,
isValidConnectionStatus
} from 'myio-js-library';
isValidDeviceStatus("warning"); // true
isValidDeviceStatus("invalid"); // false
isValidConnectionStatus("connected"); // true
isValidConnectionStatus("unknown"); // falseComplete Integration Example:
import {
calculateDeviceStatus,
getDeviceStatusInfo,
DeviceStatusType
} from 'myio-js-library';
// Calculate status from device data
const deviceStatus = calculateDeviceStatus({
connectionStatus: device.isOnline ? "online" : "offline",
lastConsumptionValue: device.powerWatts,
limitOfPowerOnStandByWatts: 100,
limitOfPowerOnAlertWatts: 1000,
limitOfPowerOnFailureWatts: 2000
});
// Get complete status information
const statusInfo = getDeviceStatusInfo(deviceStatus);
// Update UI
if (statusInfo.shouldFlash) {
element.classList.add('flash-animation');
}
element.innerHTML = `
<span class="status-icon">${statusInfo.deviceIcon}</span>
<span class="status-text">${statusInfo.deviceStatus}</span>
<span class="connection-icon">${statusInfo.connectionIcon}</span>
`;
// Handle critical states
if (deviceStatus === DeviceStatusType.FAILURE) {
sendAlert(`Device ${device.id} in critical state!`);
}Data Access Utilities
getValueByDatakey(data: any, datakey: string): any
Retrieves values from nested objects using datakey paths with dot notation and array indices.
import { getValueByDatakey } from 'myio-js-library';
const data = {
sensor: {
temperature: 25,
readings: [10, 20, 30]
}
};
getValueByDatakey(data, 'sensor.temperature'); // 25
getValueByDatakey(data, 'sensor.readings[1]'); // 20
getValueByDatakey(data, 'nonexistent.path'); // undefinedgetValueByDatakeyLegacy(dataList: any[], dataSourceNameTarget: string, dataKeyTarget: string): any
Legacy compatibility function for ThingsBoard widgets. Searches for values in data lists by matching dataSourceName and dataKey properties.
import { getValueByDatakeyLegacy } from 'myio-js-library';
const dataList = [
{ dataSourceName: 'sensor1', dataKey: 'temperature', value: 25 },
{ dataSourceName: 'sensor1', dataKey: 'humidity', value: 60 },
{ dataSourceName: 'sensor2', dataKey: 'temperature', value: 22 }
];
getValueByDatakeyLegacy(dataList, 'sensor1', 'temperature'); // 25
getValueByDatakeyLegacy(dataList, 'sensor2', 'humidity'); // undefinedfindValue(data: any, keyOrPath: string, legacyDataKey?: string): any
Unified function that supports both modern path-based access and legacy ThingsBoard-style data access.
import { findValue } from 'myio-js-library';
// Modern usage (path-based)
const modernData = { sensor: { temperature: 25 } };
findValue(modernData, 'sensor.temperature'); // 25
// Legacy usage (ThingsBoard-style)
const legacyData = [
{ dataSourceName: 'sensor1', dataKey: 'temperature', value: 25 }
];
findValue(legacyData, 'sensor1', 'temperature'); // 25DateRangePicker Component
createDateRangePicker(input: HTMLInputElement, options?: CreateDateRangePickerOptions): Promise<DateRangeControl>
Creates a MyIO-styled date range picker with Portuguese localization and timezone-aware output. This component provides a clean, user-friendly interface for selecting date ranges with built-in validation and formatting.
Parameters:
input: HTMLInputElement- The input element to attach the date range picker to (required)options?: CreateDateRangePickerOptions- Configuration options:presetStart?: string- Preset start date (ISO string or YYYY-MM-DD)presetEnd?: string- Preset end date (ISO string or YYYY-MM-DD)maxRangeDays?: number- Maximum range in days (default: 31)parentEl?: HTMLElement- Parent element for modal positioningonApply?: (result: DateRangeResult) => void- Callback when date range is applied
Returns: Promise resolving to DateRangeControl object with:
getDates(): DateRangeResult- Get current selected datessetDates(startISO: string, endISO: string): void- Set date range programmaticallydestroy(): void- Clean up and remove the picker
DateRangeResult Structure:
{
startISO: string, // "YYYY-MM-DDTHH:mm:ss-03:00" (São Paulo timezone)
endISO: string, // "YYYY-MM-DDTHH:mm:ss-03:00" (São Paulo timezone)
startLabel: string, // "DD/MM/YY HH:mm" (display format)
endLabel: string // "DD/MM/YY HH:mm" (display format)
}Key Features:
- Portuguese Localization: All labels, buttons, and formats in Brazilian Portuguese
- Timezone Aware: Outputs São Paulo timezone (-03:00) ISO strings
- Time Selection: 24-hour format time picker with minute precision
- Preset Ranges: Built-in ranges (Hoje, Últimos 7 dias, Últimos 30 dias, Mês Anterior)
- Range Validation: Configurable maximum range enforcement (default: 31 days)
- Premium Styling: MyIO brand colors and consistent design
- No Dependencies: Self-contained with automatic CDN loading of required libraries
- Accessibility: Full keyboard navigation and screen reader support
Usage Example:
import { createDateRangePicker } from 'myio-js-library';
const input = document.getElementById('date-range');
const picker = await createDateRangePicker(input, {
maxRangeDays: 31,
presetStart: '2025-09-01',
presetEnd: '2025-09-25',
onApply: (result) => {
console.log('Date range selected:', result);
// result.startISO: "2025-09-01T00:00:00-03:00"
// result.endISO: "2025-09-25T23:59:59-03:00"
// result.startLabel: "01/09/25 00:00"
// result.endLabel: "25/09/25 23:59"
}
});
// Get current selection
const dates = picker.getDates();
console.log('Current range:', dates.startISO, 'to', dates.endISO);
// Set new range programmatically
picker.setDates('2025-10-01T00:00:00-03:00', '2025-10-31T23:59:59-03:00');
// Clean up when done
picker.destroy();UMD Usage (ThingsBoard widgets):
<script src="https://unpkg.com/myio-js-library@latest/dist/myio-js-library.umd.min.js"></script>
<script>
const { createDateRangePicker } = MyIOLibrary;
(async () => {
const input = document.getElementById('dateRange');
const picker = await createDateRangePicker(input, {
maxRangeDays: 31,
onApply: (result) => {
// Update your dashboard with the selected date range
updateDashboard(result.startISO, result.endISO);
}
});
// Set default to current month
const now = new Date();
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0);
picker.setDates(
startOfMonth.toISOString(),
endOfMonth.toISOString()
);
})();
</script>Preset Ranges:
- Hoje: Current day (00:00 to 23:59)
- Últimos 7 dias: Last 7 days including today
- Últimos 30 dias: Last 30 days including today
- Mês Anterior: Previous month (full month)
Error Handling: The component includes robust error handling:
- Automatic fallback to native date inputs if dependencies fail to load
- Graceful degradation with user-friendly error messages
- Console warnings for debugging in development
Styling: The component includes premium MyIO styling with:
- Purple brand colors (#4A148C)
- Consistent button styling and hover effects
- Responsive design for mobile and desktop
- Portuguese month names and day abbreviations
Premium Date Range Input Component
createInputDateRangePickerInsideDIV(params: CreateInputDateRangePickerInsideDIVParams): Promise<DateRangeInputController>
Creates a complete, beautifully styled date range input inside a target DIV container, combining the functionality of createDateRangePicker with premium MyIO styling. This component automatically creates the HTML structure, injects styling, and provides a clean API for ThingsBoard widgets and other applications.
Parameters:
params: CreateInputDateRangePickerInsideDIVParams- Configuration object:containerId: string- The DIV id where the input will be created (required)inputId: string- The id to set on the created input (required)label?: string- Optional label text (default: "Período de Datas")placeholder?: string- Input placeholder (default: "Clique para selecionar período")pickerOptions?: CreateDateRangePickerOptions- Pass-through options for createDateRangePickerclassNames?: object- Custom CSS classes for wrapper, label, input, and helperinjectStyles?: boolean- Inject premium MyIO styling (default: true)showHelper?: boolean- Show helper text with format info (default: true)
Returns: Promise resolving to DateRangeInputController object with:
input: HTMLInputElement- The created input elementcontainer: HTMLElement- The target container elementwrapper: HTMLElement- The wrapper element created by this componentpicker: DateRangeControl- The date range picker instancegetDisplayValue(): string- Get current display value from inputgetDates(): DateRangeResult- Get current date range datasetDates(startISO: string, endISO: string): void- Set date range programmaticallysetHelperText(text: string, type?: 'default' | 'success' | 'error'): void- Update helper textdestroy(): void- Clean up and remove all created elements
Key Features:
- Automatic HTML Creation: Creates complete styled input structure inside target DIV
- Premium MyIO Styling: Beautiful styling matching demos/energy.html with purple brand colors
- Container-Based: Works with any DIV container, perfect for ThingsBoard widgets
- Accessibility Built-in: ARIA labels, keyboard navigation, screen reader support
- Responsive Design: Mobile-friendly with proper touch targets
- Error Handling: Robust validation and graceful error recovery
- Memory Management: Proper cleanup with destroy() method
Usage Example:
import { createInputDateRangePickerInsideDIV } from 'myio-js-library';
const controller = await createInputDateRangePickerInsideDIV({
containerId: 'date-picker-container',
inputId: 'energy-date-range',
label: 'Período de Análise',
pickerOptions: {
presetStart: '2025-09-01',
presetEnd: '2025-09-25',
onApply: (result) => {
console.log('Date range selected:', result);
// result.startISO: "2025-09-01T00:00:00-03:00"
// result.endISO: "2025-09-25T23:59:59-03:00"
loadEnergyData(result.startISO, result.endISO);
}
}
});
// Get current selection
const dates = controller.getDates();
console.log('Current range:', dates.startISO, 'to', dates.endISO);
// Update helper text
controller.setHelperText('Período válido selecionado', 'success');
// Clean up when done
controller.destroy();ThingsBoard Widget Integration:
<script src="https://unpkg.com/myio-js-library@latest/dist/myio-js-library.umd.min.js"></script>
<script>
const { createInputDateRangePickerInsideDIV } = MyIOLibrary;
// In your widget's onInit function
self.onInit = async function() {
try {
// Create date range picker in existing container
self.dateRangePicker = await createInputDateRangePickerInsideDIV({
containerId: 'widget-date-container',
inputId: 'energy-widget-dates',
label: 'Período de Datas',
placeholder: 'Selecione o período de análise',
pickerOptions: {
maxRangeDays: 31,
onApply: (result) => {
// Update widget state and reload data
updateWidgetData(result.startISO, result.endISO);
}
}
});
console.log('[ENERGY] Date range picker initialized successfully');
} catch (error) {
console.error('[ENERGY] Failed to initialize date picker:', error);
// Fallback to legacy implementation
initLegacyDatePicker();
}
};
// Clean up on widget destroy
self.onDestroy = function() {
if (self.dateRangePicker) {
self.dateRangePicker.destroy();
}
};
</script>Premium Styling Features:
- MyIO Brand Colors: Purple theme (#4A148C) with hover effects
- Responsive Layout: Adapts to mobile and desktop with proper spacing
- Accessibility: High contrast mode support, reduced motion support
- Visual Feedback: Hover states, focus indicators, success/error states
- Typography: Roboto font family with proper line heights
- Shadow Effects: Subtle shadows and smooth transitions
Migration from Basic Implementation:
// OLD: Manual HTML + basic styling
var $inputStart = $('input[name="startDatetimes"]');
MyIOLibrary.createDateRangePicker($inputStart[0], options);
// NEW: Automatic creation + premium styling
const controller = await MyIOLibrary.createInputDateRangePickerInsideDIV({
containerId: 'date-container',
inputId: 'startDatetimes',
label: 'Período de Datas',
pickerOptions: options
});Premium Modal Components
The library includes four premium modal components for ThingsBoard dashboards that provide comprehensive device analytics and reporting capabilities.
Token Authentication
Both AllReportModal and DeviceReportModal use a dual-token authentication system to access different API endpoints:
api.tbJwtToken- Used for ThingsBoard API endpoints (/) for device management and configurationapi.ingestionToken- Used for Data API endpoints (https://data.apps.myio-bas.com) for telemetry data access
Important: The tokens are automatically applied based on the target endpoint. You must provide the appropriate token in the API configuration:
// Example API configuration with both tokens
const apiConfig = {
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
dataApiBaseUrl: 'https://data.apps.myio-bas.com',
tbJwtToken: 'jwt-token-for-thingsboard-apis', // For ThingsBoard endpoints
ingestionToken: 'ingestion-token-for-data-apis' // For Data API endpoints
};The modals will automatically select the correct token based on the API endpoint being called:
- Data API calls (data.apps.myio-bas.com) → Uses
ingestionToken - ThingsBoard API calls (/) → Uses
tbJwtToken
openDashboardPopupReport(params: OpenDeviceReportParams): ModalHandle
Opens a device-specific daily consumption report modal with built-in date range picker, sortable table, and CSV export functionality.
Parameters:
ingestionId: string- Data ingestion identifier (required)deviceId?: string- Optional device ID for additional metadataidentifier?: string- Device identifier/code (e.g., "ENTRADA-001", "CHILLER-A")label?: string- Human-readable label/name (e.g., "Outback", "Shopping Center Norte")ui?: object- UI configuration (theme, width)api: object- API configuration:clientId?: string- Client ID for data APIclientSecret?: string- Client secret for data APIdataApiBaseUrl?: string- Data API base URLingestionToken?: string- Token for data ingestion access
Returns: ModalHandle object with:
close(): void- Close the modalon(event: 'close'|'loaded'|'error', handler: Function): void- Event listeners
Key Features:
- Built-in Date Range Picker: No need to specify dates in parameters
- Automatic Data Loading: Fetches daily consumption data for selected period
- Sortable Table: Click column headers to sort by date or consumption
- CSV Export: Download report data with proper Brazilian formatting
- Responsive Design: Works on desktop and mobile devices
- Error Handling: Graceful error display and recovery
Usage Example:
import { openDashboardPopupReport } from 'myio-js-library';
const modal = openDashboardPopupReport({
ingestionId: 'abc123-ingestion-id',
deviceId: 'device-uuid',
identifier: 'ENTRADA-001',
label: 'Outback Shopping',
api: {
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
dataApiBaseUrl: 'https://api.data.apps.myio-bas.com',
ingestionToken: 'your-ingestion-token'
}
});
modal.on('loaded', (data) => {
console.log('Report loaded:', data.count, 'days');
});
modal.on('close', () => {
console.log('Modal closed');
});openDashboardPopupAllReport(params: OpenAllReportParams): ModalHandle
Opens a customer-level energy consumption report modal with real-time data from the Customer Totals API. This modal provides comprehensive reporting across all devices for a customer with advanced sorting, filtering, and export capabilities.
Parameters:
customerId: string- ThingsBoard customer ID (required)ui?: object- UI configuration (theme, width)api: object- API configuration:clientId?: string- Client ID for data API authenticationclientSecret?: string- Client secret for data API authenticationdataApiBaseUrl?: string- Data API base URL (default: 'https://api.data.apps.myio-bas.com')
filters?: object- Optional filtering configuration:excludeLabels?: (RegExp | string)[]- Patterns to exclude devices by label
fetcher?: Function- Optional custom fetcher for testing/mocking
Returns: ModalHandle object with:
close(): void- Close the modalon(event: 'close'|'loaded'|'error', handler: Function): void- Event listeners
Key Features:
- Real Customer Totals API Integration: Calls
/api/v1/telemetry/customers/{customerId}/energy/devices/totals - Built-in Date Range Picker: Interactive date selection with validation
- Robust Data Processing: Handles pagination, fallback chains, and data normalization
- Sortable Table Structure: Sticky totals row + sortable columns (Identifier, Name, Consumption)
- Portuguese Locale Support: Brazilian number formatting and sorting
- Comprehensive Error Handling: Network failures, authentication, and validation errors
- CSV Export: Consistent formatting with UI using
MyIOLibrary.formatEnergy - Production Ready: Authentication via
fetchWithAuthpattern with automatic token refresh
Usage Example:
import { openDashboardPopupAllReport } from 'myio-js-library';
const modal = openDashboardPopupAllReport({
customerId: '73d4c75d-c311-4e98-a852-10a2231007c4',
api: {
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
dataApiBaseUrl: 'https://api.data.apps.myio-bas.com'
},
filters: {
excludeLabels: [
/bomba.*secund[aá]ria/i, // Regex patterns
/^administra[cç][aã]o\s*1$/i,
'Entrada Principal' // Exact string matches
]
}
});
modal.on('loaded', (data) => {
console.log('Customer report loaded:', data.count, 'devices');
console.log('Total consumption:', data.totalKwh, 'kWh');
});
modal.on('error', (error) => {
console.error('Report error:', error.message);
});UMD Usage (ThingsBoard widgets):
<script src="https://unpkg.com/myio-js-library@latest/dist/myio-js-library.umd.min.js"></script>
<script>
const { openDashboardPopupAllReport } = MyIOLibrary;
const modal = openDashboardPopupAllReport({
customerId: 'your-customer-id',
api: {
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
}
});
modal.on('loaded', (data) => {
console.log('All stores report loaded with', data.count, 'devices');
console.log('Grand total:', data.totalKwh, 'kWh');
});
</script>Data Flow:
User clicks "Carregar"
→ Format timestamps with timezone offset
→ Call Customer Totals API with fetchWithAuth
→ Process response with mapCustomerTotalsResponse
→ Apply sorting with applySorting (Portuguese locale)
→ Update table with updateAllReportTable
→ Update totals with updateGrandTotal
→ Enable CSV export with habilitarBotaoExportAllAPI Integration:
GET ${DATA_API_HOST}/api/v1/telemetry/customers/{customerId}/energy/devices/totals
?startTime=2025-09-01T00%3A00%3A00-03%3A00
&endTime=2025-09-25T23%3A59%3A59-03%3A00
Authorization: Bearer ${MyIOAuth.getToken()}Migration from Legacy Implementation:
// OLD: Mock/placeholder data
MyIOLibrary.openDashboardPopupAllReport({
// Used mock data or device-by-device calls
});
// NEW: Real Customer Totals API
MyIOLibrary.openDashboardPopupAllReport({
customerId: 'your-customer-id', // ✅ Real customer ID
api: {
clientId: 'your-client-id', // ✅ Real API credentials
clientSecret: 'your-client-secret'
}
// ✅ Calls real Customer Totals API endpoint
// ✅ Handles pagination automatically
// ✅ Robust error handling and recovery
});UMD Usage (ThingsBoard widgets):
<script src="https://unpkg.com/myio-js-library@latest/dist/myio-js-library.umd.min.js"></script>
<script>
const { openDashboardPopupReport } = MyIOLibrary;
const modal = openDashboardPopupReport({
ingestionId: 'demo-ingestion-123',
deviceId: 'demo-device-123',
identifier: 'ENTRADA-001',
label: 'Outback',
api: {
clientId: 'demo-client',
clientSecret: 'demo-secret',
dataApiBaseUrl: 'https://api.data.apps.myio-bas.com',
ingestionToken: 'demo-ingestion-token'
}
});
modal.on('loaded', (data) => {
console.log('Device report loaded with', data.count, 'days of data');
});
</script>openDashboardPopupWaterTank(params: OpenDashboardPopupWaterTankOptions): Promise<{ close: () => void }>
Opens a water tank telemetry modal that fetches data directly from ThingsBoard REST API (NOT Ingestion API). Displays real-time water level data with visual indicators, interactive charts, and CSV export functionality. Specifically designed for TANK and CAIXA_DAGUA device types.
Parameters:
deviceId: string- ThingsBoard device UUID (required)tbJwtToken: string- ThingsBoard JWT token for REST API authentication (required)startTs: number- Start timestamp in milliseconds (required)endTs: number- End timestamp in milliseconds (required)label?: string- Display label for the device (default: deviceId)currentLevel?: number- Current water level percentage 0-100 (optional)deviceType?: string- Device type (TANK, CAIXA_DAGUA, etc.)slaveId?: string | number- Slave device ID (optional)centralId?: string- Central controller ID (optional)telemetryKeys?: string[]- Telemetry keys to fetch (default: ['waterLevel', 'nivel', 'level'])aggregation?: string- Aggregation method: NONE, MIN, MAX, AVG, SUM, COUNT (default: 'NONE')limit?: number- Maximum data points to fetch (default: 1000, max: 10000)timezone?: string- Timezone (default: 'America/Sao_Paulo')ui?: object- UI configuration:title?: string- Modal title (default: "Water Tank - {label}")width?: number- Modal width in pixels (default: 900)height?: number- Modal height in pixels (default: 600)showExport?: boolean- Show CSV export button (default: true)showLevelIndicator?: boolean- Show visual level indicator (default: true)
onOpen?: (context) => void- Callback when modal opensonClose?: () => void- Callback when modal closesonError?: (error) => void- Callback on erroronDataLoaded?: (data) => void- Callback when telemetry data is loaded
Returns: Promise resolving to an object with:
close(): void- Method to close the modal programmatically
Key Features:
- ThingsBoard Telemetry API Integration: Fetches data directly from
/api/plugins/telemetry/DEVICE/{deviceId}/values/timeseries - Real-time Level Visualization: Interactive canvas chart showing water level trends
- Status-Based Color Coding: Critical (<20%), Low (20-40%), Medium (40-70%), Good (70-90%), Full (>90%)
- Summary Statistics: Current level, average, minimum, maximum values
- Device Metadata Display: Shows device ID, label, type, slave ID, central ID
- CSV Export: Download telemetry data with proper Brazilian formatting
- Responsive Design: Adapts to different screen sizes with smooth animations
- Error Handling: Graceful error display with user-friendly messages
Usage Example:
import { openDashboardPopupWaterTank } from 'myio-js-library';
// Basic usage
const modal = await openDashboardPopupWaterTank({
deviceId: 'water-tank-uuid-123',
tbJwtToken: localStorage.getItem('jwt_token'),
startTs: Date.now() - 86400000 * 7, // Last 7 days
endTs: Date.now(),
label: 'Water Tank - Building A',
currentLevel: 75.5
});
// Close programmatically
modal.close();
// Advanced usage with callbacks and customization
const modal = await openDashboardPopupWaterTank({
deviceId: 'caixa-dagua-uuid-456',
tbJwtToken: myToken,
startTs: startTimestamp,
endTs: endTimestamp,
label: 'Caixa D\'Água Principal',
deviceType: 'CAIXA_DAGUA',
currentLevel: 82.3,
slaveId: 'SLAVE-001',
centralId: 'CENTRAL-A',
telemetryKeys: ['waterLevel', 'nivel_agua', 'level'],
aggregation: 'AVG',
limit: 500,
ui: {
title: 'Análise de Nível - Caixa Principal',
width: 1000,
height: 700,
showExport: true
},
onOpen: (context) => {
console.log('Modal opened for device:', context.device.label);
console.log('Time range:', new Date(context.timeRange.startTs), '-', new Date(context.timeRange.endTs));
},
onDataLoaded: (data) => {
console.log('Telemetry loaded:', data.telemetry.length, 'points');
console.log('Summary:', data.summary);
},
onClose: () => {
console.log('Modal closed');
},
onError: (error) => {
console.error('Error:', error.message);
alert(`Failed to load water tank data: ${error.message}`);
}
});UMD Usage (ThingsBoard widgets):
<script src="https://unpkg.com/myio-js-library@latest/dist/myio-js-library.umd.min.js"></script>
<script>
const { openDashboardPopupWaterTank } = MyIOLibrary;
// In your widget action handler
async function handleDashboardAction() {
const jwtToken = localStorage.getItem('jwt_token');
const deviceId = entityId.id;
const startTs = ctx.timeWindow.minTime;
const endTs = ctx.timeWindow.maxTime;
try {
const modal = await openDashboardPopupWaterTank({
deviceId: deviceId,
tbJwtToken: jwtToken,
startTs: startTs,
endTs: endTs,
label: entityName,
deviceType: 'CAIXA_DAGUA',
currentLevel: currentLevelValue,
onOpen: (context) => {
console.log('Water tank modal opened');
},
onError: (error) => {
console.error('Modal error:', error);
showNotification(error.message, 'error');
}
});
} catch (error) {
console.error('Failed to open water tank modal:', error);
}
}
</script>ThingsBoard API Integration:
GET /api/plugins/telemetry/DEVICE/{deviceId}/values/timeseries
?keys=waterLevel,nivel,level
&startTs={startMillis}
&endTs={endMillis}
&limit=1000
Headers:
X-Authorization: Bearer {tbJwtToken}Level Status Color Coding:
- Critical (<20%): Red (#e74c3c) - Risk of running dry
- Low (20-40%): Orange (#e67e22) - Needs attention
- Medium (40-70%): Yellow (#f39c12) - Normal range
- Good (70-90%): Green (#27ae60) - Optimal level
- Full (>90%): Blue (#3498db) - Near capacity
Data Structure Returned:
{
deviceId: 'device-uuid',
telemetry: [
{ ts: 1704067200000, value: 75.5, key: 'waterLevel' },
{ ts: 1704153600000, value: 72.3, key: 'waterLevel' }
],
summary: {
currentLevel: 75.5, // Most recent reading
avgLevel: 73.8, // Average over period
minLevel: 65.2, // Minimum level
maxLevel: 82.1, // Maximum level
totalReadings: 245, // Number of data points
firstReadingTs: 1704067200000,
lastReadingTs: 1704672000000
},
metadata: {
keys: ['waterLevel', 'nivel', 'level'],
aggregation: 'NONE',
limit: 1000
}
}Error Handling: The modal includes comprehensive error handling with specific error codes:
VALIDATION_ERROR- Invalid parameters providedAUTH_ERROR- Authentication failed (invalid or expired token)TOKEN_EXPIRED- JWT token has expiredNETWORK_ERROR- Network request failedNO_DATA- Device not found or no telemetry availableUNKNOWN_ERROR- Unexpected error occurred
Integration with TELEMETRY Widget: The modal automatically integrates with the v5.2.0 TELEMETRY widget controller:
// Automatic device type detection and routing
if (deviceType === 'TANK' || deviceType === 'CAIXA_DAGUA') {
// Opens water tank modal (uses TB telemetry API)
await MyIOLibrary.openDashboardPopupWaterTank({
deviceId: deviceId,
tbJwtToken: jwtToken,
startTs: startTimestamp,
endTs: endTimestamp,
label: deviceLabel,
currentLevel: levelPercentage
});
} else {
// Opens energy/water modal (uses Ingestion API)
await MyIO.openDashboardPopupEnergy({...});
}Migration from Legacy API:
// OLD API (deprecated)
MyIOLibrary.openDashboardPopupReport({
ingestionId: 'demo-ingestion-123',
deviceLabel: 'Entrada Subestação', // ❌ Deprecated
storeLabel: 'Outback', // ❌ Deprecated
date: { start: '2025-09-01', end: '2025-09-25' }, // ❌ Deprecated
api: { tbJwtToken: 'jwt-token' } // ❌ Deprecated
});
// NEW API (recommended)
MyIOLibrary.openDashboardPopupReport({
ingestionId: 'demo-ingestion-123',
identifier: 'ENTRADA-001', // ✅ Clear device identifier
label: 'Outback', // ✅ Clear human-readable name
api: { ingestionToken: 'ingestion-token' } // ✅ Clear token purpose
});MYIO Components - Drag-to-Footer Dock Implementation
The library includes three main interactive components for building comparative selection interfaces:
MyIOSelectionStore - Global Selection Management
A singleton store for managing device selection state, multi-unit totals, and analytics.
import { MyIOSelectionStore } from 'myio-js-library';
// Register entities for selection
MyIOSelectionStore.registerEntity({
id: 'device-001',
name: 'Solar Panel North',
icon: 'energy',
group: 'RENEWABLE_ENERGY',
lastValue: 145.6,
unit: 'kWh'
});
// Listen to selection changes
MyIOSelectionStore.on('selection:change', (data) => {
console.log('Selection changed:', data.selectedIds);
console.log('Totals:', data.totals);
});
// Manage selections
MyIOSelectionStore.add('device-001');
MyIOSelectionStore.toggle('device-002');
MyIOSelectionStore.clear();
// Get current state
const selectedIds = MyIOSelectionStore.getSelectedIds();
const totals = MyIOSelectionStore.getTotals();
const display = MyIOSelectionStore.getMultiUnitTotalDisplay();
// Returns: "Energy: 1,234 kWh | Water: 567 m³"
// Open comparison modal
MyIOSelectionStore.openComparison();Key Features:
- Global state management - Singleton pattern for app-wide selection state
- Multi-unit calculations - Automatic totals for energy (kWh), water (m³), temperature (°C)
- Event system - React to selection changes with custom callbacks
- Analytics integration - Built-in tracking for user interactions
- Time-series data - Cached data fetching for chart visualization
- Accessibility - Screen reader announcements and ARIA support
MyIODraggableCard - Interactive Device Cards
Reusable card components with drag-and-drop, checkbox synchronization, and accessibility.
import { MyIODraggableCard } from 'myio-js-library';
const container = document.getElementById('device-grid');
const entity = {
id: 'pump-001',
name: 'Water Pump Main',
icon: 'water',
group: 'HYDRAULIC_SYSTEM',
lastValue: 234.7,
unit: 'm³',
status: 'ok'
};
// Create draggable card
const card = new MyIODraggableCard(container, entity, {
showCheckbox: true,
draggable: true,
className: 'custom-card'
});
// Update entity data
card.updateEntity({
lastValue: 156.8,
status: 'alert'
});
// Manual selection control
card.setSelected(true);
// Cleanup
card.destroy();Key Features:
- Drag & Drop - HTML5 drag API with touch support (long-press on mobile)
- Checkbox sync - Two-way synchronization with SelectionStore
- Keyboard navigation - Full accessibility with Tab, Enter, Space, Delete
- Visual states - Connection status, data freshness, selection indicators
- Auto-formatting - Brazilian locale number formatting
- Icon system - Built-in SVG icons for energy, water, temperature, etc.
MyIOChartModal - Comparative Visualization
Interactive chart modal with Chart.js integration and export functionality.
import { MyIOChartModal } from 'myio-js-library';
// The modal automatically integrates with SelectionStore
// When user selects devices and clicks "Compare", modal opens automatically
// Manual control (optional)
const data = {
entities: MyIOSelectionStore.getSelectedEntities(),
totals: MyIOSelectionStore.getTotals(),
count: MyIOSelectionStore.getSelectionCount()
};
await MyIOChartModal.open(data);
// Export functions
MyIOChartModal.exportCsv(); // Downloads CSV file
MyIOChartModal.exportPng(); // Downloads chart as PNG
MyIOChartModal.exportPdf(); // Placeholder for future implementation
MyIOChartModal.close();Key Features:
- Chart.js integration - Auto-loads Chart.js from CDN
- Multiple chart types - Line charts and bar charts
- Time range selection - 7, 14, or 30-day comparisons
- Export functionality - CSV and PNG export with timestamps
- Responsive design - Adapts to container size
- Accessibility - ARIA dialog, keyboard navigation, focus management
- Analytics tracking - Automatic event tracking for user interactions
Complete Integration Example
<!DOCTYPE html>
<html>
<head>
<title>Device Comparison Dashboard</title>
</head>
<body>
<div class="app">
<div class="device-grid" id="deviceGrid"></div>
<div class="selection-summary" id="summary"></div>
<button id="compareBtn">Compare Selected</button>
</div>
<!-- Load MYIO library -->
<script src="https://unpkg.com/myio-js-library@latest/dist/myio-js-library.umd.min.js"></script>
<