"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var MeterCC_exports = {};
__export(MeterCC_exports, {
  MeterCC: () => MeterCC,
  MeterCCAPI: () => MeterCCAPI,
  MeterCCGet: () => MeterCCGet,
  MeterCCReport: () => MeterCCReport,
  MeterCCReset: () => MeterCCReset,
  MeterCCSupportedGet: () => MeterCCSupportedGet,
  MeterCCSupportedReport: () => MeterCCSupportedReport,
  MeterCCValues: () => import_CCValues_generated.MeterCCValues,
  isAccumulatedValue: () => isAccumulatedValue
});
module.exports = __toCommonJS(MeterCC_exports);
var import_tslib = require("tslib");
var __validateArgs = __toESM(require("./MeterCC._validateArgs.js"), 1);
var import_core = require("@zwave-js/core");
var import_shared = require("@zwave-js/shared");
var import_API = require("../lib/API.js");
var import_CommandClass = require("../lib/CommandClass.js");
var import_CommandClassDecorators = require("../lib/CommandClassDecorators.js");
var import_Types = require("../lib/_Types.js");
var import_CCValues_generated = require("./_CCValues.generated.js");
const { validateArgs_MeterCCAPI_get, validateArgs_MeterCCAPI_sendReport, validateArgs_MeterCCAPI_getAll, validateArgs_MeterCCAPI_sendSupportedReport, validateArgs_MeterCCAPI_reset } = __validateArgs;
function splitPropertyKey(key) {
  return {
    rateType: key & 255,
    scale: key >>> 8 & 255,
    meterType: key >>> 16
  };
}
__name(splitPropertyKey, "splitPropertyKey");
function getValueLabel(meterType, scale, rateType, suffix) {
  let ret = (0, import_core.getMeterName)(meterType);
  const scaleLabel = ((0, import_core.getMeterScale)(meterType, scale) ?? (0, import_core.getUnknownMeterScale)(scale)).label;
  switch (rateType) {
    case import_Types.RateType.Consumed:
      ret += ` Consumption [${scaleLabel}]`;
      break;
    case import_Types.RateType.Produced:
      ret += ` Production [${scaleLabel}]`;
      break;
    default:
      ret += ` [${scaleLabel}]`;
  }
  if (suffix) {
    ret += ` (${suffix})`;
  }
  return ret;
}
__name(getValueLabel, "getValueLabel");
function parseMeterValueAndInfo(data, offset) {
  (0, import_core.validatePayload)(data.length >= offset + 1);
  const type = data[offset] & 31;
  const rateType = (data[offset] & 96) >>> 5;
  const scale1Bit2 = (data[offset] & 128) >>> 7;
  const { scale: scale1Bits10, value, bytesRead } = (0, import_core.parseFloatWithScale)(data.subarray(offset + 1));
  return {
    type,
    rateType,
    // The scale is composed of two fields
    scale1: scale1Bit2 << 2 | scale1Bits10,
    value,
    // We've read one byte more than the float contains
    bytesRead: bytesRead + 1
  };
}
__name(parseMeterValueAndInfo, "parseMeterValueAndInfo");
function encodeMeterValueAndInfo(type, rateType, scale, value) {
  const scale1 = scale >= 7 ? 7 : scale & 7;
  const scale1Bits10 = scale1 & 3;
  const scale1Bit2 = scale1 >>> 2;
  const scale2 = scale >= 7 ? scale - 7 : void 0;
  const typeByte = type & 31 | (rateType & 3) << 5 | scale1Bit2 << 7;
  const floatParams = (0, import_core.getFloatParameters)(value);
  const valueBytes = (0, import_core.encodeFloatWithScale)(value, scale1Bits10, floatParams);
  return {
    data: import_shared.Bytes.concat([[typeByte], valueBytes]),
    floatParams: (0, import_shared.pick)(floatParams, ["precision", "size"]),
    scale2
  };
}
__name(encodeMeterValueAndInfo, "encodeMeterValueAndInfo");
function parseScale(scale1, data, scale2Offset) {
  if (scale1 === 7) {
    (0, import_core.validatePayload)(data.length >= scale2Offset + 1);
    const scale2 = data[scale2Offset];
    return scale1 + scale2;
  } else {
    return scale1;
  }
}
__name(parseScale, "parseScale");
function isAccumulatedValue(meterType, scale) {
  switch (meterType) {
    case 1:
      return (
        // kVarh
        // Pulse count
        scale === 0 || scale === 1 || scale === 3 || scale === 8
      );
    case 2:
      return (
        // Pulse count
        // ft³
        scale === 0 || scale === 1 || scale === 3
      );
    case 3:
      return (
        // Pulse count
        // US gallons
        scale === 0 || scale === 1 || scale === 2 || scale === 3
      );
    case 4:
      return scale === 0;
    // kWh
    case 5:
      return scale === 0;
  }
  return false;
}
__name(isAccumulatedValue, "isAccumulatedValue");
let MeterCCAPI = (() => {
  let _classDecorators = [(0, import_CommandClassDecorators.API)(import_core.CommandClasses.Meter)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = import_API.PhysicalCCAPI;
  let _instanceExtraInitializers = [];
  let _get_decorators;
  let _sendReport_decorators;
  let _getAll_decorators;
  let _sendSupportedReport_decorators;
  let _reset_decorators;
  var MeterCCAPI2 = class extends _classSuper {
    static {
      __name(this, "MeterCCAPI");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(this, null, _get_decorators, { kind: "method", name: "get", static: false, private: false, access: { has: /* @__PURE__ */ __name((obj) => "get" in obj, "has"), get: /* @__PURE__ */ __name((obj) => obj.get, "get") }, metadata: _metadata }, null, _instanceExtraInitializers);
      (0, import_tslib.__esDecorate)(this, null, _sendReport_decorators, { kind: "method", name: "sendReport", static: false, private: false, access: { has: /* @__PURE__ */ __name((obj) => "sendReport" in obj, "has"), get: /* @__PURE__ */ __name((obj) => obj.sendReport, "get") }, metadata: _metadata }, null, _instanceExtraInitializers);
      (0, import_tslib.__esDecorate)(this, null, _getAll_decorators, { kind: "method", name: "getAll", static: false, private: false, access: { has: /* @__PURE__ */ __name((obj) => "getAll" in obj, "has"), get: /* @__PURE__ */ __name((obj) => obj.getAll, "get") }, metadata: _metadata }, null, _instanceExtraInitializers);
      (0, import_tslib.__esDecorate)(this, null, _sendSupportedReport_decorators, { kind: "method", name: "sendSupportedReport", static: false, private: false, access: { has: /* @__PURE__ */ __name((obj) => "sendSupportedReport" in obj, "has"), get: /* @__PURE__ */ __name((obj) => obj.sendSupportedReport, "get") }, metadata: _metadata }, null, _instanceExtraInitializers);
      (0, import_tslib.__esDecorate)(this, null, _reset_decorators, { kind: "method", name: "reset", static: false, private: false, access: { has: /* @__PURE__ */ __name((obj) => "reset" in obj, "has"), get: /* @__PURE__ */ __name((obj) => obj.reset, "get") }, metadata: _metadata }, null, _instanceExtraInitializers);
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MeterCCAPI2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
    supportsCommand(cmd) {
      switch (cmd) {
        case import_Types.MeterCommand.Get:
        case import_Types.MeterCommand.Report:
          return true;
        // This is mandatory
        case import_Types.MeterCommand.SupportedGet:
        case import_Types.MeterCommand.SupportedReport:
          return this.version >= 2;
        case import_Types.MeterCommand.Reset: {
          const ret = this.tryGetValueDB()?.getValue({
            commandClass: (0, import_CommandClassDecorators.getCommandClass)(this),
            endpoint: this.endpoint.index,
            property: "supportsReset"
          });
          return ret === true;
        }
      }
      return super.supportsCommand(cmd);
    }
    get [import_API.POLL_VALUE]() {
      return async function({ property, propertyKey }) {
        switch (property) {
          case "value":
          case "previousValue":
          case "deltaTime": {
            if (propertyKey == void 0) {
              (0, import_API.throwMissingPropertyKey)(this.ccId, property);
            } else if (typeof propertyKey !== "number") {
              (0, import_API.throwUnsupportedPropertyKey)(this.ccId, property, propertyKey);
            }
            const { rateType, scale } = splitPropertyKey(propertyKey);
            return (await this.get({
              rateType,
              scale
            }))?.[property];
          }
          default:
            (0, import_API.throwUnsupportedProperty)(this.ccId, property);
        }
      };
    }
    async get(options) {
      this.assertSupportsCommand(import_Types.MeterCommand, import_Types.MeterCommand.Get);
      const cc = new MeterCCGet({
        nodeId: this.endpoint.nodeId,
        endpointIndex: this.endpoint.index,
        ...options
      });
      const response = await this.host.sendCommand(cc, this.commandOptions);
      if (response) {
        return {
          type: response.type,
          scale: (0, import_core.getMeterScale)(response.type, response.scale) ?? (0, import_core.getUnknownMeterScale)(response.scale),
          ...(0, import_shared.pick)(response, [
            "value",
            "previousValue",
            "rateType",
            "deltaTime"
          ])
        };
      }
    }
    async sendReport(options) {
      this.assertSupportsCommand(import_Types.MeterCommand, import_Types.MeterCommand.Report);
      const cc = new MeterCCReport({
        nodeId: this.endpoint.nodeId,
        endpointIndex: this.endpoint.index,
        ...options
      });
      return this.host.sendCommand(cc, this.commandOptions);
    }
    async getAll(accumulatedOnly = false) {
      const valueDB = this.tryGetValueDB();
      if (this.version >= 2) {
        const meterType = valueDB?.getValue(import_CCValues_generated.MeterCCValues.type.endpoint(this.endpoint.index));
        const supportedScales = valueDB?.getValue(import_CCValues_generated.MeterCCValues.supportedScales.endpoint(this.endpoint.index)) ?? [];
        const supportedRateTypes = valueDB?.getValue(import_CCValues_generated.MeterCCValues.supportedRateTypes.endpoint(this.endpoint.index)) ?? [];
        const rateTypes = supportedRateTypes.length ? supportedRateTypes : [void 0];
        const ret = [];
        for (const rateType of rateTypes) {
          for (const scale of supportedScales) {
            if (accumulatedOnly && meterType != void 0 && !isAccumulatedValue(meterType, scale)) {
              continue;
            }
            const response = await this.get({
              scale,
              rateType
            });
            if (response)
              ret.push(response);
          }
        }
        return ret;
      } else {
        const response = await this.get();
        return response ? [response] : [];
      }
    }
    // oxlint-disable-next-line typescript/explicit-module-boundary-types
    async getSupported() {
      this.assertSupportsCommand(import_Types.MeterCommand, import_Types.MeterCommand.SupportedGet);
      const cc = new MeterCCSupportedGet({
        nodeId: this.endpoint.nodeId,
        endpointIndex: this.endpoint.index
      });
      const response = await this.host.sendCommand(cc, this.commandOptions);
      if (response) {
        return (0, import_shared.pick)(response, [
          "type",
          "supportsReset",
          "supportedScales",
          "supportedRateTypes"
        ]);
      }
    }
    async sendSupportedReport(options) {
      this.assertSupportsCommand(import_Types.MeterCommand, import_Types.MeterCommand.SupportedReport);
      const cc = new MeterCCSupportedReport({
        nodeId: this.endpoint.nodeId,
        endpointIndex: this.endpoint.index,
        ...options
      });
      await this.host.sendCommand(cc, this.commandOptions);
    }
    async reset(options) {
      this.assertSupportsCommand(import_Types.MeterCommand, import_Types.MeterCommand.Reset);
      const cc = new MeterCCReset({
        nodeId: this.endpoint.nodeId,
        endpointIndex: this.endpoint.index,
        ...options
      });
      return this.host.sendCommand(cc, this.commandOptions);
    }
    get [(_get_decorators = [validateArgs_MeterCCAPI_get()], _sendReport_decorators = [validateArgs_MeterCCAPI_sendReport()], _getAll_decorators = [validateArgs_MeterCCAPI_getAll()], _sendSupportedReport_decorators = [validateArgs_MeterCCAPI_sendSupportedReport()], _reset_decorators = [validateArgs_MeterCCAPI_reset()], import_API.SET_VALUE)]() {
      return async function({ property, propertyKey }, value) {
        if (property !== "reset") {
          (0, import_API.throwUnsupportedProperty)(this.ccId, property);
        } else if (propertyKey != void 0 && typeof propertyKey !== "number") {
          (0, import_API.throwUnsupportedPropertyKey)(this.ccId, property, propertyKey);
        } else if (value !== true) {
          (0, import_API.throwWrongValueType)(this.ccId, property, "true", value === false ? "false" : typeof value);
        }
        if (typeof propertyKey === "number") {
          const { meterType, scale, rateType } = splitPropertyKey(propertyKey);
          return this.reset({
            type: meterType,
            scale,
            rateType,
            targetValue: 0
          });
        } else {
          return this.reset();
        }
        return void 0;
      };
    }
    [import_API.SET_VALUE_HOOKS] = ((0, import_tslib.__runInitializers)(this, _instanceExtraInitializers), ({ property, propertyKey }, _value, _options) => {
      if (property !== "reset")
        return;
      if (typeof propertyKey === "number") {
        const { meterType, rateType, scale } = splitPropertyKey(propertyKey);
        const readingValueId = import_CCValues_generated.MeterCCValues.value(meterType, rateType, scale).endpoint(this.endpoint.index);
        return {
          optimisticallyUpdateRelatedValues: /* @__PURE__ */ __name((supervisedAndSuccessful) => {
            if (!supervisedAndSuccessful)
              return;
            const valueDB = this.tryGetValueDB();
            if (!valueDB)
              return;
            if (isAccumulatedValue(meterType, scale)) {
              valueDB.setValue({
                commandClass: this.ccId,
                endpoint: this.endpoint.index,
                property,
                propertyKey
              }, 0);
            }
          }, "optimisticallyUpdateRelatedValues"),
          verifyChanges: /* @__PURE__ */ __name(() => {
            this.schedulePoll(readingValueId, 0, { transition: "fast" });
          }, "verifyChanges")
        };
      } else {
        const valueDB = this.tryGetValueDB();
        if (!valueDB)
          return;
        const accumulatedValues = valueDB.findValues((vid) => vid.commandClass === this.ccId && vid.endpoint === this.endpoint.index && import_CCValues_generated.MeterCCValues.value.is(vid)).filter(({ propertyKey: propertyKey2 }) => {
          if (typeof propertyKey2 !== "number")
            return false;
          const { meterType, scale } = splitPropertyKey(propertyKey2);
          return isAccumulatedValue(meterType, scale);
        });
        return {
          optimisticallyUpdateRelatedValues: /* @__PURE__ */ __name((supervisedAndSuccessful) => {
            if (!supervisedAndSuccessful)
              return;
            for (const value of accumulatedValues) {
              valueDB.setValue(value, 0);
            }
          }, "optimisticallyUpdateRelatedValues"),
          verifyChanges: /* @__PURE__ */ __name(() => {
            for (const valueID of accumulatedValues) {
              this.schedulePoll(valueID, 0, { transition: "fast" });
            }
          }, "verifyChanges")
        };
      }
    });
  };
  return MeterCCAPI2 = _classThis;
})();
let MeterCC = (() => {
  let _classDecorators = [(0, import_CommandClassDecorators.commandClass)(import_core.CommandClasses.Meter), (0, import_CommandClassDecorators.implementedVersion)(6), (0, import_CommandClassDecorators.ccValues)(import_CCValues_generated.MeterCCValues)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = import_CommandClass.CommandClass;
  var MeterCC2 = class extends _classSuper {
    static {
      __name(this, "MeterCC");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MeterCC2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
    async interview(ctx) {
      const node = this.getNode(ctx);
      const endpoint = this.getEndpoint(ctx);
      const api = import_API.CCAPI.create(import_core.CommandClasses.Meter, ctx, endpoint).withOptions({
        priority: import_core.MessagePriority.NodeQuery
      });
      ctx.logNode(node.id, {
        endpoint: this.endpointIndex,
        message: `Interviewing ${this.ccName}...`,
        direction: "none"
      });
      if (api.version >= 2) {
        ctx.logNode(node.id, {
          endpoint: this.endpointIndex,
          message: "querying meter support...",
          direction: "outbound"
        });
        const suppResp = await api.getSupported();
        if (suppResp) {
          const logMessage = `received meter support:
type:                 ${(0, import_core.getMeterName)(suppResp.type)}
supported scales:     ${suppResp.supportedScales.map((s) => ((0, import_core.getMeterScale)(suppResp.type, s) ?? (0, import_core.getUnknownMeterScale)(s)).label).map((label) => `
\xB7 ${label}`).join("")}
supported rate types: ${suppResp.supportedRateTypes.map((rt) => (0, import_shared.getEnumMemberName)(import_Types.RateType, rt)).map((label) => `
\xB7 ${label}`).join("")}
supports reset:       ${suppResp.supportsReset}`;
          ctx.logNode(node.id, {
            endpoint: this.endpointIndex,
            message: logMessage,
            direction: "inbound"
          });
        } else {
          ctx.logNode(node.id, {
            endpoint: this.endpointIndex,
            message: "Querying meter support timed out, skipping interview...",
            level: "warn"
          });
          return;
        }
      }
      await this.refreshValues(ctx);
      this.setInterviewComplete(ctx, true);
    }
    async refreshValues(ctx, options) {
      const node = this.getNode(ctx);
      const endpoint = this.getEndpoint(ctx);
      const api = import_API.CCAPI.create(import_core.CommandClasses.Meter, ctx, endpoint).withOptions({
        priority: options?.priority ?? import_core.MessagePriority.NodeQuery
      });
      if (api.version === 1) {
        ctx.logNode(node.id, {
          endpoint: this.endpointIndex,
          message: `querying default meter value...`,
          direction: "outbound"
        });
        await api.get();
      } else {
        const type = this.getValue(ctx, import_CCValues_generated.MeterCCValues.type) ?? 0;
        const supportedScales = this.getValue(ctx, import_CCValues_generated.MeterCCValues.supportedScales) ?? [];
        const supportedRateTypes = this.getValue(ctx, import_CCValues_generated.MeterCCValues.supportedRateTypes) ?? [];
        const rateTypes = supportedRateTypes.length ? supportedRateTypes : [void 0];
        for (const rateType of rateTypes) {
          for (const scale of supportedScales) {
            ctx.logNode(node.id, {
              endpoint: this.endpointIndex,
              message: `querying meter value (type = ${(0, import_core.getMeterName)(type)}, scale = ${((0, import_core.getMeterScale)(type, scale) ?? (0, import_core.getUnknownMeterScale)(scale)).label}${rateType != void 0 ? `, rate type = ${(0, import_shared.getEnumMemberName)(import_Types.RateType, rateType)}` : ""})...`,
              direction: "outbound"
            });
            await api.get({ scale, rateType });
          }
        }
      }
    }
    shouldRefreshValues(ctx) {
      const valueDB = ctx.tryGetValueDB(this.nodeId);
      if (!valueDB)
        return true;
      const values = this.getDefinedValueIDs(ctx).filter((v) => import_CCValues_generated.MeterCCValues.value.is(v));
      return values.every((v) => {
        const lastUpdated = valueDB.getTimestamp(v);
        return lastUpdated == void 0 || Date.now() - lastUpdated > import_core.timespan.hours(6);
      });
    }
    /**
     * Returns which type this meter has.
     * This only works AFTER the interview process
     */
    static getMeterTypeCached(ctx, endpoint) {
      return ctx.getValueDB(endpoint.nodeId).getValue(import_CCValues_generated.MeterCCValues.type.endpoint(endpoint.index));
    }
    /**
     * Returns which scales are supported by this meter.
     * This only works AFTER the interview process
     */
    static getSupportedScalesCached(ctx, endpoint) {
      return ctx.getValueDB(endpoint.nodeId).getValue(import_CCValues_generated.MeterCCValues.supportedScales.endpoint(endpoint.index));
    }
    /**
     * Returns whether reset is supported by this meter.
     * This only works AFTER the interview process
     */
    static supportsResetCached(ctx, endpoint) {
      return ctx.getValueDB(endpoint.nodeId).getValue(import_CCValues_generated.MeterCCValues.supportsReset.endpoint(endpoint.index));
    }
    /**
     * Returns which rate types are supported by this meter.
     * This only works AFTER the interview process
     */
    static getSupportedRateTypesCached(ctx, endpoint) {
      return ctx.getValueDB(endpoint.nodeId).getValue(import_CCValues_generated.MeterCCValues.supportedRateTypes.endpoint(endpoint.index));
    }
    translatePropertyKey(ctx, property, propertyKey) {
      if (property === "value" && typeof propertyKey === "number") {
        const { meterType, rateType, scale } = splitPropertyKey(propertyKey);
        let ret;
        if (meterType !== 0) {
          ret = `${(0, import_core.getMeterName)(meterType)}_${((0, import_core.getMeterScale)(meterType, scale) ?? (0, import_core.getUnknownMeterScale)(scale)).label}`;
        } else {
          ret = "default";
        }
        if (rateType !== import_Types.RateType.Unspecified) {
          ret += "_" + (0, import_shared.getEnumMemberName)(import_Types.RateType, rateType);
        }
        return ret;
      } else if (property === "reset" && typeof propertyKey === "number") {
        return (0, import_core.getMeterName)(propertyKey);
      }
      return super.translatePropertyKey(ctx, property, propertyKey);
    }
  };
  return MeterCC2 = _classThis;
})();
let MeterCCReport = (() => {
  let _classDecorators = [(0, import_CommandClassDecorators.CCCommand)(import_Types.MeterCommand.Report)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = MeterCC;
  var MeterCCReport2 = class extends _classSuper {
    static {
      __name(this, "MeterCCReport");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MeterCCReport2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
    constructor(options) {
      super(options);
      this.type = options.type;
      this.scale = options.scale;
      this.value = options.value;
      this.previousValue = options.previousValue;
      this.rateType = options.rateType ?? import_Types.RateType.Unspecified;
      this.deltaTime = options.deltaTime ?? import_core.UNKNOWN_STATE;
    }
    static from(raw, ctx) {
      const { type, rateType, scale1, value, bytesRead } = parseMeterValueAndInfo(raw.payload, 0);
      let offset = bytesRead;
      const floatSize = bytesRead - 2;
      let deltaTime;
      let previousValue;
      if (raw.payload.length >= offset + 2) {
        deltaTime = raw.payload.readUInt16BE(offset);
        offset += 2;
        if (deltaTime === 65535) {
          deltaTime = import_core.UNKNOWN_STATE;
        }
        if (
          // Previous value is included only if delta time is not 0
          deltaTime !== 0 && raw.payload.length >= offset + floatSize
        ) {
          const { value: prevValue } = (0, import_core.parseFloatWithScale)(
            // This float is split in the payload
            import_shared.Bytes.concat([
              [raw.payload[1]],
              raw.payload.subarray(offset)
            ])
          );
          offset += floatSize;
          previousValue = prevValue;
        }
      } else {
        deltaTime = 0;
      }
      const scale = parseScale(scale1, raw.payload, offset);
      return new this({
        nodeId: ctx.sourceNodeId,
        type,
        rateType,
        value,
        deltaTime,
        previousValue,
        scale
      });
    }
    persistValues(ctx) {
      if (!super.persistValues(ctx))
        return false;
      const ccVersion = (0, import_CommandClass.getEffectiveCCVersion)(ctx, this);
      const meter = (0, import_core.getMeter)(this.type);
      const scale = (0, import_core.getMeterScale)(this.type, this.scale) ?? (0, import_core.getUnknownMeterScale)(this.scale);
      const measurementValidation = !ctx.getDeviceConfig?.(this.nodeId)?.compat?.disableStrictMeasurementValidation;
      if (measurementValidation) {
        import_core.validatePayload.withReason(`Unknown meter type ${(0, import_shared.num2hex)(this.type)} or corrupted data`)(!!meter);
        import_core.validatePayload.withReason(`Unknown meter scale ${(0, import_shared.num2hex)(this.scale)} or corrupted data`)(scale.label !== (0, import_core.getUnknownMeterScale)(this.scale).label);
        if (ccVersion >= 2) {
          const expectedType = this.getValue(ctx, import_CCValues_generated.MeterCCValues.type);
          if (expectedType != void 0) {
            import_core.validatePayload.withReason("Unexpected meter type or corrupted data")(this.type === expectedType);
          }
          const supportedScales = this.getValue(ctx, import_CCValues_generated.MeterCCValues.supportedScales);
          if (supportedScales?.length) {
            import_core.validatePayload.withReason(`Unsupported meter scale ${scale.label} or corrupted data`)(supportedScales.includes(this.scale));
          }
          const supportedRateTypes = this.getValue(ctx, import_CCValues_generated.MeterCCValues.supportedRateTypes);
          if (supportedRateTypes?.length) {
            import_core.validatePayload.withReason(`Unsupported rate type ${(0, import_shared.getEnumMemberName)(import_Types.RateType, this.rateType)} or corrupted data`)(supportedRateTypes.includes(this.rateType));
          }
        }
      }
      const valueValue = import_CCValues_generated.MeterCCValues.value(this.type, this.rateType, this.scale);
      this.setMetadata(ctx, valueValue, {
        ...valueValue.meta,
        label: getValueLabel(this.type, this.scale, this.rateType),
        unit: scale.unit,
        ccSpecific: {
          meterType: this.type,
          scale: this.scale,
          rateType: this.rateType
        }
      });
      this.setValue(ctx, valueValue, this.value);
      return true;
    }
    type;
    scale;
    value;
    previousValue;
    rateType;
    deltaTime;
    serialize(ctx) {
      const { data: typeAndValue, floatParams, scale2 } = encodeMeterValueAndInfo(this.type, this.rateType, this.scale, this.value);
      const deltaTime = this.deltaTime ?? 65535;
      const deltaTimeBytes = new import_shared.Bytes(2);
      deltaTimeBytes.writeUInt16BE(deltaTime, 0);
      this.payload = import_shared.Bytes.concat([
        typeAndValue,
        deltaTimeBytes
      ]);
      if (this.deltaTime !== 0 && this.previousValue != void 0) {
        const prevValueBytes = (0, import_core.encodeFloatWithScale)(
          this.previousValue,
          0,
          // we discard the scale anyways
          floatParams
        ).subarray(1);
        this.payload = import_shared.Bytes.concat([
          this.payload,
          prevValueBytes
        ]);
      }
      if (scale2 != void 0) {
        this.payload = import_shared.Bytes.concat([
          this.payload,
          [scale2]
        ]);
      }
      return super.serialize(ctx);
    }
    toLogEntry(ctx) {
      const scale = (0, import_core.getMeterScale)(this.type, this.scale) ?? (0, import_core.getUnknownMeterScale)(this.scale);
      const message = {
        "meter type": (0, import_core.getMeterName)(this.type),
        scale: scale.label,
        "rate type": (0, import_shared.getEnumMemberName)(import_Types.RateType, this.rateType),
        value: this.value
      };
      if (this.deltaTime !== import_core.UNKNOWN_STATE) {
        message["time delta"] = `${this.deltaTime} seconds`;
      }
      if (this.previousValue != void 0) {
        message["prev. value"] = this.previousValue;
      }
      return {
        ...super.toLogEntry(ctx),
        message
      };
    }
  };
  return MeterCCReport2 = _classThis;
})();
function testResponseForMeterGet(sent, received) {
  return (sent.scale == void 0 || sent.scale === received.scale) && (sent.rateType == void 0 || sent.rateType == received.rateType);
}
__name(testResponseForMeterGet, "testResponseForMeterGet");
let MeterCCGet = (() => {
  let _classDecorators = [(0, import_CommandClassDecorators.CCCommand)(import_Types.MeterCommand.Get), (0, import_CommandClassDecorators.expectedCCResponse)(MeterCCReport, testResponseForMeterGet)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = MeterCC;
  var MeterCCGet2 = class extends _classSuper {
    static {
      __name(this, "MeterCCGet");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MeterCCGet2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
    constructor(options) {
      super(options);
      this.rateType = options.rateType;
      this.scale = options.scale;
    }
    static from(raw, ctx) {
      let rateType;
      let scale;
      if (raw.payload.length >= 1) {
        rateType = (raw.payload[0] & 192) >>> 6;
        scale = (raw.payload[0] & 56) >>> 3;
        if (scale === 7) {
          (0, import_core.validatePayload)(raw.payload.length >= 2);
          scale += raw.payload[1];
        }
      }
      return new this({
        nodeId: ctx.sourceNodeId,
        rateType,
        scale
      });
    }
    rateType;
    scale;
    serialize(ctx) {
      let scale1;
      let scale2;
      let bufferLength = 0;
      const ccVersion = (0, import_CommandClass.getEffectiveCCVersion)(ctx, this);
      if (this.scale == void 0) {
        scale1 = 0;
      } else if (ccVersion >= 4 && this.scale >= 7) {
        scale1 = 7;
        scale2 = this.scale >>> 3;
        bufferLength = 2;
      } else if (ccVersion >= 3) {
        scale1 = this.scale & 7;
        bufferLength = 1;
      } else if (ccVersion >= 2) {
        scale1 = this.scale & 3;
        bufferLength = 1;
      } else {
        scale1 = 0;
      }
      let rateTypeFlags = 0;
      if (ccVersion >= 4 && this.rateType != void 0) {
        rateTypeFlags = this.rateType & 3;
        bufferLength = Math.max(bufferLength, 1);
      }
      this.payload = import_shared.Bytes.alloc(bufferLength, 0);
      this.payload[0] = rateTypeFlags << 6 | scale1 << 3;
      if (scale2)
        this.payload[1] = scale2;
      return super.serialize(ctx);
    }
    toLogEntry(ctx) {
      const message = {};
      if (this.rateType != void 0) {
        message["rate type"] = (0, import_shared.getEnumMemberName)(import_Types.RateType, this.rateType);
      }
      if (this.scale != void 0) {
        if (ctx) {
          const type = this.getValue(ctx, import_CCValues_generated.MeterCCValues.type);
          if (type != void 0) {
            message.scale = ((0, import_core.getMeterScale)(type, this.scale) ?? (0, import_core.getUnknownMeterScale)(this.scale)).label;
          }
        } else {
          message.scale = this.scale;
        }
      }
      return {
        ...super.toLogEntry(ctx),
        message
      };
    }
  };
  return MeterCCGet2 = _classThis;
})();
let MeterCCSupportedReport = (() => {
  let _classDecorators = [(0, import_CommandClassDecorators.CCCommand)(import_Types.MeterCommand.SupportedReport), (0, import_CommandClassDecorators.ccValueProperty)("type", import_CCValues_generated.MeterCCValues.type), (0, import_CommandClassDecorators.ccValueProperty)("supportsReset", import_CCValues_generated.MeterCCValues.supportsReset), (0, import_CommandClassDecorators.ccValueProperty)("supportedScales", import_CCValues_generated.MeterCCValues.supportedScales), (0, import_CommandClassDecorators.ccValueProperty)("supportedRateTypes", import_CCValues_generated.MeterCCValues.supportedRateTypes)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = MeterCC;
  var MeterCCSupportedReport2 = class extends _classSuper {
    static {
      __name(this, "MeterCCSupportedReport");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MeterCCSupportedReport2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
    constructor(options) {
      super(options);
      this.type = options.type;
      this.supportsReset = options.supportsReset;
      this.supportedScales = options.supportedScales;
      this.supportedRateTypes = options.supportedRateTypes;
    }
    static from(raw, ctx) {
      (0, import_core.validatePayload)(raw.payload.length >= 2);
      const type = raw.payload[0] & 31;
      const supportsReset = !!(raw.payload[0] & 128);
      const hasMoreScales = !!(raw.payload[1] & 128);
      let supportedScales;
      if (hasMoreScales) {
        (0, import_core.validatePayload)(raw.payload.length >= 3);
        const extraBytes = raw.payload[2];
        (0, import_core.validatePayload)(raw.payload.length >= 3 + extraBytes);
        supportedScales = (0, import_core.parseBitMask)(import_shared.Bytes.concat([
          [raw.payload[1] & 127],
          raw.payload.subarray(3, 3 + extraBytes)
        ]), 0).map((scale) => scale >= 8 ? scale - 1 : scale);
      } else {
        supportedScales = (0, import_core.parseBitMask)(import_shared.Bytes.from([raw.payload[1]]), 0);
      }
      const supportedRateTypes = (0, import_core.parseBitMask)(import_shared.Bytes.from([(raw.payload[0] & 96) >>> 5]), 1);
      return new this({
        nodeId: ctx.sourceNodeId,
        type,
        supportsReset,
        supportedScales,
        supportedRateTypes
      });
    }
    type;
    supportsReset;
    supportedScales;
    supportedRateTypes;
    persistValues(ctx) {
      if (!super.persistValues(ctx))
        return false;
      if (!this.supportsReset)
        return true;
      const ccVersion = (0, import_CommandClass.getEffectiveCCVersion)(ctx, this);
      if (ccVersion < 6) {
        this.ensureMetadata(ctx, import_CCValues_generated.MeterCCValues.resetAll);
      } else {
        for (const scale of this.supportedScales) {
          if (!isAccumulatedValue(this.type, scale))
            continue;
          for (const rateType of this.supportedRateTypes) {
            const resetSingleValue = import_CCValues_generated.MeterCCValues.resetSingle(this.type, rateType, scale);
            this.ensureMetadata(ctx, resetSingleValue, {
              ...resetSingleValue.meta,
              label: `Reset ${getValueLabel(this.type, scale, rateType)}`
            });
          }
        }
      }
      return true;
    }
    serialize(ctx) {
      const typeByte = this.type & 31 | (this.supportedRateTypes.includes(import_Types.RateType.Consumed) ? 32 : 0) | (this.supportedRateTypes.includes(import_Types.RateType.Produced) ? 64 : 0) | (this.supportsReset ? 128 : 0);
      const supportedScales = (0, import_core.encodeBitMask)(
        this.supportedScales,
        void 0,
        // The first byte only has 7 bits for the bitmask,
        // so we add a fake bit for the value -1 and later shift
        // the first byte one to the right
        -1
      );
      const scalesByte1 = supportedScales[0] >>> 1 | (supportedScales.length > 1 ? 128 : 0);
      this.payload = import_shared.Bytes.from([
        typeByte,
        scalesByte1
      ]);
      if (supportedScales.length > 1) {
        this.payload = import_shared.Bytes.concat([
          this.payload,
          [supportedScales.length - 1],
          import_shared.Bytes.from(supportedScales.subarray(1))
        ]);
      }
      return super.serialize(ctx);
    }
    toLogEntry(ctx) {
      const message = {
        "meter type": (0, import_core.getMeterName)(this.type),
        "supports reset": this.supportsReset,
        "supported scales": this.supportedScales.map((scale) => `
\xB7 ${((0, import_core.getMeterScale)(this.type, scale) ?? (0, import_core.getUnknownMeterScale)(scale)).label}`).join(""),
        "supported rate types": this.supportedRateTypes.map((rt) => (0, import_shared.getEnumMemberName)(import_Types.RateType, rt)).join(", ")
      };
      return {
        ...super.toLogEntry(ctx),
        message
      };
    }
  };
  return MeterCCSupportedReport2 = _classThis;
})();
let MeterCCSupportedGet = (() => {
  let _classDecorators = [(0, import_CommandClassDecorators.CCCommand)(import_Types.MeterCommand.SupportedGet), (0, import_CommandClassDecorators.expectedCCResponse)(MeterCCSupportedReport)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = MeterCC;
  var MeterCCSupportedGet2 = class extends _classSuper {
    static {
      __name(this, "MeterCCSupportedGet");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MeterCCSupportedGet2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
  };
  return MeterCCSupportedGet2 = _classThis;
})();
let MeterCCReset = (() => {
  let _classDecorators = [(0, import_CommandClassDecorators.CCCommand)(import_Types.MeterCommand.Reset), (0, import_CommandClassDecorators.useSupervision)()];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = MeterCC;
  var MeterCCReset2 = class extends _classSuper {
    static {
      __name(this, "MeterCCReset");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MeterCCReset2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
    constructor(options) {
      super(options);
      this.type = options.type;
      this.scale = options.scale;
      this.rateType = options.rateType;
      this.targetValue = options.targetValue;
    }
    static from(raw, ctx) {
      if (raw.payload.length === 0) {
        return new this({
          nodeId: ctx.sourceNodeId
        });
      }
      const { type, rateType, scale1, value: targetValue, bytesRead: scale2Offset } = parseMeterValueAndInfo(raw.payload, 0);
      const scale = parseScale(scale1, raw.payload, scale2Offset);
      return new this({
        nodeId: ctx.sourceNodeId,
        type,
        rateType,
        targetValue,
        scale
      });
    }
    type;
    scale;
    rateType;
    targetValue;
    serialize(ctx) {
      if (this.type != void 0 && this.scale != void 0 && this.rateType != void 0 && this.targetValue != void 0) {
        const { data: typeAndValue, scale2 } = encodeMeterValueAndInfo(this.type, this.rateType, this.scale, this.targetValue);
        this.payload = typeAndValue;
        if (scale2 != void 0) {
          this.payload = import_shared.Bytes.concat([
            this.payload,
            [scale2]
          ]);
        }
      }
      return super.serialize(ctx);
    }
    toLogEntry(ctx) {
      const message = {};
      if (this.type != void 0) {
        message.type = (0, import_core.getMeterName)(this.type);
      }
      if (this.rateType != void 0) {
        message["rate type"] = (0, import_shared.getEnumMemberName)(import_Types.RateType, this.rateType);
      }
      if (this.type != void 0 && this.scale != void 0) {
        message.scale = ((0, import_core.getMeterScale)(this.type, this.scale) ?? (0, import_core.getUnknownMeterScale)(this.scale)).label;
      }
      if (this.targetValue != void 0) {
        message["target value"] = this.targetValue;
      }
      return {
        ...super.toLogEntry(ctx),
        message
      };
    }
  };
  return MeterCCReset2 = _classThis;
})();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  MeterCC,
  MeterCCAPI,
  MeterCCGet,
  MeterCCReport,
  MeterCCReset,
  MeterCCSupportedGet,
  MeterCCSupportedReport,
  MeterCCValues,
  isAccumulatedValue
});
//# sourceMappingURL=MeterCC.js.map
