Milesight UC501: Multi-Interface-SDI-12-LoRaWAN-Controller
Milesight UC501 Multi-Interface-LoRaWAN-Controller: SDI-12, RS485 Modbus, Analog- und GPIO-Eingaenge, eigenes Decoder-Framework und ChirpStack-Integration.
- LoRaWAN
- Class A / Class C, OTAA
- SDI-12
- Mehrere SDI-12-Sensoren
- Feldbus
- RS485 Modbus RTU
- Eingaenge
- GPIO (DI/DO/Zaehler) + Analog (4-20 mA / 0-10 V)
- Gehaeuse
- IP67, fuer den Aussenbereich
- Stromversorgung
- Batterie, Solar oder externe DC-Quelle
- Konfiguration
- NFC / USB (Milesight ToolBox)
Was kann der UC501?
SDI-12-Sensoren
Wetter-, Hydrologie- und Agrarsonden, als ASCII-String gelesen.
RS485 Modbus RTU
Energiezaehler, SPS und industrielle Modbus-Sensoren.
Analogeingaenge (AI)
4-20 mA / 0-10 V mit Min-, Max- und Durchschnittswert.
GPIO
Pro Kanal Digitaleingang, Digitalausgang oder Impulszaehler.
Verlaufsspeicher
Speichert Messwerte lokal und sendet sie nach einer Netzluecke erneut.
Integration
Sensor / Controller
Misst oder steuert vor Ort und sendet LoRaWAN-Uplinks.
LoRaWAN-Gateway
Empfängt die Funkpakete und reicht sie an den Server weiter.
ChirpStack
Network-Server: verwaltet Sessions und decodiert das Payload.
ThingsBoard / Grafana
Dashboards, Alarme, Regeln und Reports.
function decodeUplink(input) {
var bytes = input.bytes;
var data = { gpio: {}, analog: {}, sdi12: {}, modbus: {} };
for (var i = 0; i < bytes.length; ) {
var channel = bytes[i++];
var type = bytes[i++];
// Modbus: register id + package type, then 1/2/4 bytes by data type.
// Checked before the 0xff device-info catch-all so the type byte 0x0e
// is not swallowed by the generic 0xff branch (channel 0x80 or 0xff).
if ((channel === 0x80 || channel === 0xff) && type === 0x0e) {
var reg = bytes[i++] - 6;
var dataType = bytes[i++] & 0x07;
data.modbus["chn" + reg] = readModbusValue(bytes, i, dataType);
i += modbusLen(dataType); continue;
}
// Device info (join / power-on): version, SN, class. Lengths are firmware-specific.
if (channel === 0xff) { i += deviceInfoLen(type); continue; }
// Battery (%)
if (channel === 0x01 && type === 0x75) { data.battery = bytes[i]; i += 1; continue; }
// GPIO as digital input / output: 1 byte (0/1)
if ((channel === 0x03 || channel === 0x04) && (type === 0x00 || type === 0x01)) {
data.gpio["ch" + channel] = bytes[i]; i += 1; continue;
}
// GPIO as pulse counter: UINT32 little-endian (4 bytes)
if ((channel === 0x03 || channel === 0x04) && type === 0xc8) {
data.gpio["ch" + channel] = readUInt32LE(bytes, i); i += 4; continue;
}
// Analog input: value + min + max + avg, four INT16 little-endian (8 bytes)
if ((channel === 0x05 || channel === 0x06) && type === 0x02) {
data.analog["ch" + channel] = {
value: readInt16LE(bytes, i) / 1000,
min: readInt16LE(bytes, i + 2) / 1000,
max: readInt16LE(bytes, i + 4) / 1000,
avg: readInt16LE(bytes, i + 6) / 1000
};
i += 8; continue;
}
// SDI-12: 1 byte sensor index + 36-byte ASCII string
if (channel === 0x08 && type === 0xdb) {
var idx = bytes[i++];
data.sdi12["s" + (idx + 1)] = readString(bytes, i, 36); i += 36; continue;
}
break; // unknown channel: stop, payload layout is configuration-dependent
}
return { data: data };
}
function modbusLen(t) { return (t <= 1) ? 1 : (t <= 3) ? 2 : 4; }
function readModbusValue(b, i, t) {
if (t <= 1) return b[i];
if (t <= 3) return readUInt16LE(b, i);
if (t === 5 || t === 7) return readFloatLE(b, i);
return readUInt32LE(b, i);
}
function readInt16LE(b, i) {
var v = (b[i + 1] << 8) | b[i];
return v > 0x7fff ? v - 0x10000 : v;
}
function readUInt16LE(b, i) { return (b[i + 1] << 8) | b[i]; }
function readUInt32LE(b, i) {
return ((b[i+3]<<24)|(b[i+2]<<16)|(b[i+1]<<8)|b[i]) >>> 0;
}
function readFloatLE(b, i) {
var bits = readUInt32LE(b, i);
var sign = (bits >>> 31) ? -1 : 1;
var exp = (bits >>> 23) & 0xff;
var frac = bits & 0x7fffff;
if (exp === 0) return sign * frac * Math.pow(2, -149);
if (exp === 0xff) return frac ? NaN : sign * Infinity;
return sign * (1 + frac * Math.pow(2, -23)) * Math.pow(2, exp - 127);
}
function readString(b, i, len) {
var s = "";
for (var k = 0; k < len; k++) {
if (b[i + k] === 0) break;
s += String.fromCharCode(b[i + k]);
}
return s.replace(/[^\x20-\x7e]/g, "").trim();
}
function deviceInfoLen(type) {
void type; // 0xFF segment lengths are firmware-specific; set per deployment
return 1;
}
Implementiert nach der veröffentlichten Milesight-Byte-Spezifikation (Communication Protocol / User Guide).
Die UC501-Payload ist konfigurationsabhaengig: Sie spiegelt wider, welche Schnittstellen aktiviert sind (SDI-12, RS485 Modbus, Analog, GPIO) und wie die Register zugeordnet sind. SDI-12-Messwerte kommen als Sensorindex plus 36-Byte-ASCII-String, den Sie je Sonde parsen; Modbus-Werte kommen als Registernummer plus Datentyp, der die Laenge bestimmt (1/2/4 Byte). Das ist ein Framework, implementiert nach der veroeffentlichten Milesight-Byte-Spezifikation, kein fertiges Drop-in: Wir finalisieren den Decoder anhand eines echten Uplinks aus dem Einsatz. Die Analog- und Float-Skalierung unterscheidet sich je nach Hardware-/Firmware-Revision (etwa /1000 statt /100), pruefen Sie sie an Ihrem Geraet.
Konfiguration & Stolpersteine
Schnittstellenauswahl
SDI-12, RS485, Analog und GPIO werden in der ToolBox aktiviert; die Payload enthaelt nur die eingeschalteten Kanaele, daher ist der Decoder geraetespezifisch.
SDI-12-Adressierung
Jede SDI-12-Sonde braucht eine eindeutige Busadresse und ein definiertes Messkommando. Dokumentieren Sie die Adress-zu-Sensor-Zuordnung, damit die ASCII-Strings nachvollziehbar bleiben.
Class-C-Stromverbrauch
Class C haelt das Empfangsfenster fuer Downlinks offen und braucht mehr Strom; fuer SDI-12-Feldstandorte auf Batterie oder Solar passt Class A mit geplantem Reporting meist besser.
Verlauf-Nachuebertragung
Die UC501 puffert Messwerte lokal und sendet sie nach einer Netzluecke erneut, daher sollten Dashboards Verlaufsframes gegen Live-Uplinks entdoppeln.
So unterstützt dich merkaio beim UC501
Von der Beschaffung bis zum laufenden Betrieb, alles aus einer Hand und auf eigener europäischer Infrastruktur.
Pre-Staging & Provisioning
Wir konfigurieren den UC501, setzen Keys, Intervalle und Alarme und liefern einsatzbereit aus.
Eigener Decoder
Payload-Codec für ChirpStack v4 und ThingsBoard, nach der Milesight-Spezifikation implementiert.
Integration ins Dashboard
Die Daten landen in deinem ThingsBoard oder Grafana, inklusive Alarmen und Reports.
Betrieb & Monitoring
Wir betreiben LoRaWAN-Stack und Dashboards auf europäischer Infrastruktur, du nutzt nur die Daten.
Häufige Fragen
Sprechen wir über Ihre Infrastruktur. Digital und vor Ort.
Ob IoT-Plattformentwicklung, Hardwareauswahl, Managed Hosting für ChirpStack, ThingsBoard, Grafana oder NetBird VPN, oder Migration von einem Self-Hosted-Setup - wir finden die passende Lösung für Ihren Anwendungsfall. Buchen Sie ein kostenloses 30-Minuten-Gespräch, unverbindlich.
Ihr Ansprechpartner
Timo Wevelsiep
Gründer, merkaio
15 Minuten, unverbindlich, direkt mit Timo.
Decoder für ChirpStack v4. merkaio ist unabhängiger Integrator und nicht mit Milesight affiliiert.