Seite 1 von 1

Modbus Wert mit sendCommand schreiben / Umwandlung string --> int

Verfasst: 15. Aug 2024 21:13
von chilobo
Ich versuche gerade, ein Bundle für eine Wärmepumpe zu schreiben. Für die Übergabe der PV-Überschussleistung muss ich einen Wert in ein Register mit 2 Byte, also Datentyp int schreiben.
Der Channel im Thing hat den Parametertyp number:Power, entsprechend hat auch das Item, das ich dafür generiere, den Parametertyp number:Power.
Wenn ich jetzt mit

Code: Alles auswählen

int P_Available = 1234
lambdahp_actual_power.sendCommand(P_Available)
einen Wert an das Item sende, bekommt er vom Item die Einheit W angehängt und wird auch so (als String ?) an den Code des Bundles übergeben.
Damit kommt mein abgekupfertes Binding nicht zurecht, es erwartet eine Zahl.

Ich habe mir jetzt erst mal so beholfen, dass ich dem Channel ein zweites Item lambdahp_actual_power_number verlinkt habe, das den Parametertyp number hat. Dann kommt der Code damit klar.

Das ist natürlich etwas unschön, denn die Nutzer des Bundles müssten das dann auch machen: Ein Item zum Lesen mit der passenden Einheit W, ein anderes zum Schreiben ohne Einheit. Das ist etwas unlogisch.
Sicher gibt es eine Funktion (in Java), mit der man den an den Code übergebenen String in einen Integerwert übersetzen kann.
Konkreter: Alles, was nicht {0..9, +, -} ist, aus dem String löschen und daraus einen Integerwert machen.

Ergänzung: Müsste der Code dafür nicht irgendwo im Quelltext des modbus-Bundle versteckt sein, denn der thing-type data erzeugt ja diverse channels Value as Number .. Value as Rollershutter und kann dann wohl auch mit sendCommand an die verschiedenen Datentypen umgehen.

Re: Modbus Wert mit sendCommand schreiben / Umwandlung string --> int

Verfasst: 15. Aug 2024 22:33
von udo1toni
Welchen Teil vom Modbus Binding verwendest Du denn?

Du kannst das Profile modbus:gainOffset nutzen, um in Read-Richtung eine Einheit zu setzen und diese in Write-Richtung auch wieder zu entfernen. Einen number:Power Channel gibt es jedoch nicht.

Re: Modbus Wert mit sendCommand schreiben / Umwandlung string --> int

Verfasst: 16. Aug 2024 12:32
von chilobo
Ich habe aufbauend auf dem StiebelEltron-Bundle ein eigenes Bundle gebastelt. Das wird dann ein OSGI-Bundle, das an das modbus-Bundle angehängt ist. Von den Channels des data-Bundles, das vom Modbus-Code bei github miterzeugt wird, habe ich nur geschrieben, um zu verdeutlichen, dass dort der nötige Code eigentlich vorhanden sein muss.

modbus:gainOffset hört sich sehr interessant an. Ich habe erst suchen müssen, wo ich es finde. Im UI, dort wo der Link vom Channel zum Item dargestellt ist, findet man es im unteren Teil. Ich vermute, es ist das Feld Gain-Offset Correction. Damit werde ich jetzt experimentieren und melde mich dann wieder.

Re: Modbus Wert mit sendCommand schreiben / Umwandlung string --> int

Verfasst: 16. Aug 2024 15:35
von chilobo
Hm - so ganz konsistent ist das nicht. Mein Binding versieht den Wert der Leistung beim Lesen der Überschussleistung mit der Einheit W und übergibt sie dann auch damit vom Channel an das Item. Das ist auch nach der neuen "Politik" des Umgangs mit Einheiten richtig. Wenn ich bei diesem Channel dann Gain-Offset Correction verwenden will, kommt eine Fehlermeldung:

Code: Alles auswählen

Profile can only process plain numbers from handler. Got unit W.
Also muss man entweder:
- Im Binding beim Auslesen und Schreiben die Einheit mitdurchreichen (und beim internen Schreiben ins Register löschen).
oder
- Im Binding nur mit Zahlen arbeiten und dann mit der gain-Offset Correction die Umwandlung bei der Übergabe zwischen Binding und Item machen lassen.

Re: Modbus Wert mit sendCommand schreiben / Umwandlung string --> int

Verfasst: 16. Aug 2024 19:37
von udo1toni
Ah, dann ist Dein Binding "zu gut" :) Ich kenne mich mit der Erstellung von Addons nicht aus, aber man kann nicht einfach die Einheit hinter den Wert schreiben, der Wert muss dann explizit als QuantityType markiert sein, im Fall von Leistung halt QuantityType<Power>, damit openHAB mit dem W überhaupt was anfangen kann. Gewöhnlich kommt über Modbus niemals eine Einheit mit, das ist im Standard nicht vorgesehen. Stattdessen liest Du ein Register und "weißt", dass es ich beim dem Wert um Watt handelt, so dass Du diese Information dann in der Konfiguration einbauen kannst.
Das Modbus Binding ist meines Wissens bisher noch nicht für QuantityType vorbereitet, gain-Offset erscheint mir auch nur als Workaround, man müsste für jeden number Channel explizit die Unit setzen können, um konsistent zu anderen Universal-Bindings zu sein (z.B. mqtt, http).

Re: Modbus Wert mit sendCommand schreiben / Umwandlung string --> int

Verfasst: 17. Aug 2024 11:40
von chilobo
Das sehe ich auch so. Neuerdings ist es aber wohl so, dass man bei einem Binding die entsprechenden Einheiten mit erzeugt, diese werden dann von den Items übernommen. Oder?

Für das Lesen der Werte aus der Wärmepumpe habe ich im Code des StiebelEltronBindings eine getScaled-Funktion gefunden und damit eine entsprechende getUnscaled-Funktion geschrieben:

Code: Alles auswählen

 protected State getScaled(Number value, Unit<?> unit) {
        return QuantityType.valueOf(value.doubleValue() / 10, unit);
    }

    protected State getUnscaled(Number value, Unit<?> unit) {
        return QuantityType.valueOf(value.doubleValue(), unit);
    }
Bei meiner Wärmepumpe werden Temperaturwerte in 1/10 °C geführt, dort rufe ich dann getScaled auf:

Code: Alles auswählen

 updateState(channelUID(GROUP_GENERAL_AMBIENT, CHANNEL_ACTUAL_AMBIENT_TEMPERATURE),
                getScaled(block.actualAmbientTemperature, CELSIUS));
        resetCommunicationError();
Leistungswerte werden als "ganze" Watt geführt, dort rufe ich dann getUnscaled auf:

Code: Alles auswählen

updateState(channelUID(GROUP_GENERAL_EMANAGER, CHANNEL_ACTUAL_POWER_CONSUMPTION),
                getUnscaled(block.actualPowerConsumption, WATT));

Beim Schreiben habe ich bisher nur Leistungen (Überschuss der PV-Anlage) geschrieben, das geht im Binding mit den Funktionen:

Code: Alles auswählen

 private short getInt16Value(Command command) throws LambdaException {
        if (command instanceof QuantityType quantityCommand) {
            QuantityType<?> c = quantityCommand.toUnit(WATT);
            if (c != null) {
                return c.shortValue();
            } else {
                throw new LambdaException("Unsupported unit");
            }
        }
        if (command instanceof DecimalType c) {
            return c.shortValue();
        }
        throw new LambdaException("Unsupported command type");
    }
und

Code: Alles auswählen

    protected void writeInt16(int address, short shortValue) {
        LambdaConfiguration myconfig = LambdaHandler.this.config;
        ModbusCommunicationInterface mycomms = LambdaHandler.this.comms;

        if (myconfig == null || mycomms == null) {
            throw new IllegalStateException("registerPollTask called without proper configuration");
        }
        // big endian byte ordering
        byte hi = (byte) (shortValue >> 8);
        byte lo = (byte) shortValue;
        ModbusRegisterArray data = new ModbusRegisterArray(hi, lo);

        ModbusWriteRegisterRequestBlueprint request = new ModbusWriteRegisterRequestBlueprint(slaveId, address, data,
                true, myconfig.getMaxTries());
        // 15.8.24 13:40 war:
        // false, myconfig.getMaxTries());

        mycomms.submitOneTimeWrite(request, result -> {
            if (hasConfigurationError()) {
                return;
            }
            logger.trace("Successful write, matching request {}", request);
            LambdaHandler.this.updateStatus(ThingStatus.ONLINE);
        }, failure -> {
            LambdaHandler.this.handleWriteError(failure);
            logger.trace("Unsuccessful write, matching request {}", request);
        });
    }
Da ich auch Temperturwerte schreiben möchte (z.Bsp: Zieltemperatur des Brauchwassers), muss ich da wohl weitere Funktionen schreiben oder Einheit und Faktor als weitere Parameter an die beiden Funktionen übergeben.
Wie könnte der Code dann aussehen?

Oder ich versuche, den Code von modbus:gainOffset zu finden und den zu verwenden. Eine Diskussion dazu lese ich mir dann durch:
https://community.openhab.org/t/modbus- ... its/110814

Re: Modbus Wert mit sendCommand schreiben / Umwandlung string --> int

Verfasst: 17. Aug 2024 21:06
von udo1toni
Ja, der Punkt ist halt, das Binding muss QuantityType unterstützen. Ich denke nicht, dass es ausreicht, einfach den Datentyp zu verwenden. Aber wie gesagt, ich bin kein Entwickler, ich nutze das Zeug nur :)