@mehrwiedu/ecowitt-api
v0.1.3
Published
Transport-independent TypeScript SDK for local Ecowitt weather gateway integrations
Maintainers
Readme
@mehrwiedu/ecowitt-api
Transport-independent TypeScript SDK for local Ecowitt weather gateway integrations.
The package provides a high-level client, an MQTT transport, payload parsing, normalized weather observations, sensor diagnostics, unknown-field preservation, and log-safe payload sanitizing. It is intended to serve as the shared protocol layer for applications such as an ioBroker adapter.
Current status
The package currently provides:
- a transport-independent
EcowittClient, - an MQTT client transport,
- parsing of URL-encoded Ecowitt payloads,
- gateway metadata extraction,
- typed and normalized weather measurements,
- typed piezo-rain measurements,
- typed WS90 diagnostic values,
- preservation of unknown fields,
- preservation of the original raw message,
- masking of sensitive payload fields,
- reconnect and transport-state events,
- unsubscribe-capable event listeners,
- TypeScript declarations and native ECMAScript modules.
The MQTT path has been validated live with an Ecowitt GW2000A gateway and a WS90 outdoor sensor.
Requirements
- Node.js 22 or newer
- ECMAScript modules
Installation
npm install @mehrwiedu/ecowitt-apiQuick start with MQTT
import {
EcowittClient,
EcowittMqttTransport,
} from "@mehrwiedu/ecowitt-api";
const transport = new EcowittMqttTransport({
url: "mqtt://192.168.178.10:1883",
topicFilter: "ecowitt/#",
username: "ecowitt",
password: process.env.ECOWITT_MQTT_PASSWORD,
clientId: `my-ecowitt-client-${process.pid}`,
clean: true,
reconnectPeriodMs: 1000,
connectTimeoutMs: 30000,
});
const client = new EcowittClient({
transport,
});
client.onStateChanged((state) => {
console.log("Ecowitt state:", state);
});
client.onObservation((observation) => {
console.log(
observation.gatewayId,
observation.observedAt,
observation.measurements,
);
});
client.onDiagnostic((diagnostic, observation) => {
console.log(
observation.gatewayId,
diagnostic.sensorModel,
diagnostic.kind,
diagnostic.value,
diagnostic.unit,
);
});
client.onError((error, message) => {
console.error(
"Ecowitt error:",
error.message,
message?.topic,
);
});
await client.connect();Disconnect the client during application shutdown:
await client.disconnect();Client events
EcowittClient exposes the following event APIs:
onRawMessage(handler)onObservation(handler)onDiagnostic(handler)onStateChanged(handler)onError(handler)
Every registration method returns an unsubscribe callback:
const unsubscribe = client.onObservation((observation) => {
console.log(observation.gatewayId);
});
unsubscribe();The client forwards transport states and parses every received raw message into an EcowittObservation.
Parser errors are emitted through onError() and do not disconnect the transport. Exceptions thrown by raw-message, observation, diagnostic, or state listeners are also converted into client error events. Errors thrown by error handlers themselves are ignored to prevent recursive error emission.
MQTT transport
import {
EcowittMqttTransport,
} from "@mehrwiedu/ecowitt-api";
const transport = new EcowittMqttTransport({
url: "mqtt://192.168.178.10:1883",
username: "ecowitt",
password: "secret",
topicFilter: "ecowitt/#",
});Supported options:
urlusernamepasswordtopicFilterclientIdcleanreconnectPeriodMsconnectTimeoutMs
Defaults:
topicFilter:ecowitt/#clean:truereconnectPeriodMs:1000connectTimeoutMs:30000
The transport exposes these states:
disconnectedconnectingconnecteddisconnectingreconnectingerror
Both connect() and disconnect() are safe to call repeatedly.
Parsing a payload directly
The parser can also be used independently from a transport:
import {
EcowittMeasurementKind,
parseEcowittPayload,
type RawEcowittMessage,
} from "@mehrwiedu/ecowitt-api";
const message: RawEcowittMessage = {
transport: "mqtt-client",
topic: "ecowitt/3076F567649B",
receivedAt: new Date(),
payload:
"PASSKEY=secret"
+ "&stationtype=GW2000A_V3.3.1"
+ "&dateutc=2026-07-22%2010%3A23%3A19"
+ "&model=GW2000A"
+ "&tempf=64.58"
+ "&humidity=69"
+ "&windspeedmph=2.01"
+ "&rrain_piezo=0.008"
+ "&ws90cap_volt=5.3"
+ "&wh90batt=3.28"
+ "&ws90_ver=161",
};
const observation = parseEcowittPayload(message);
const outdoorTemperature = observation.measurements.find(
measurement =>
measurement.kind
=== EcowittMeasurementKind.OutdoorTemperature,
);
console.log(observation.gateway);
console.log(outdoorTemperature);
console.log(observation.diagnostics);
console.log(observation.unknownFields);Values are normalized to public SI-oriented units where appropriate:
- Fahrenheit to degrees Celsius,
- miles per hour to metres per second,
- inches of rain to millimetres,
- inches of mercury to hectopascals.
Every typed measurement retains its original field name and raw value.
Observation structure
EcowittObservation contains:
gatewayIdobservedAtreceivedAtgatewaymeasurementsdiagnosticsunknownFieldsrawMessage
Unknown fields are deliberately retained so that new Ecowitt firmware fields and additional sensor values are not silently discarded.
Sanitizing payloads
Ecowitt payloads may contain sensitive values such as PASSKEY or password. Sanitize a payload before writing it to logs:
import {
sanitizeEcowittPayload,
} from "@mehrwiedu/ecowitt-api";
const safePayload = sanitizeEcowittPayload(
"PASSKEY=secret&tempf=64.58",
);
console.log(safePayload);Field-name matching is case-insensitive.
Recognized gateway metadata
modelstationtyperuntimeheapdns_err_cntfreqintervaldateutc
Recognized measurements
Gateway and weather data
tempinfhumidityinbaromrelinbaromabsintempfhumidityvpdwinddirwinddir_avg10mwindspeedmphwindgustmphmaxdailygustsolarradiationuv
WS90 piezo rain
rrain_piezoerain_piezohrain_piezolast24hrain_piezodrain_piezowrain_piezomrain_piezoyrain_piezosrain_piezo
WS90 diagnostics
ws90cap_voltwh90battws90_ver
Public API
The package exports:
EcowittClientEcowittMqttTransportnormalizeEcowittMqttClientOptionsparseEcowittPayloadsanitizeEcowittPayloadEcowittPayloadErrorEcowittMeasurementKindEcowittMeasurementUnitEcowittSensorDiagnosticKindEcowittSensorDiagnosticUnit
It also exports the corresponding public TypeScript types for clients, transports, raw messages, observations, gateways, measurements, diagnostics, unknown fields, MQTT options, transport states, handlers, and unsubscribe callbacks.
See docs/API.md for the full API reference.
Examples
examples/mqtt-live.mjs: raw MQTT transportexamples/parser-live.mjs: MQTT transport plus direct parser usageexamples/client-live.mjs: complete high-level client pathexamples/iobroker-integration.mjs: adapter-oriented integration pattern
Development
npm install
npm run checknpm run check performs:
- TypeScript type checking
- unit tests
- a clean production build
Architecture
The design and transport boundaries are documented in docs/ARCHITECTURE.md.
License
MIT
