calculation of dewpoint
The dewpoint is a value for deciding weather air should/could be exchangened in order to lower/raise relative humidity. Unfortunatly most thermometer/hygrometer-combinations do not report this value. As dewpoint my be calculated by knowing temperature and relative humidity an extension would be nice. Having basic coding skills this should be doable for me, but I do not have any clue where to start. Basicly the code should do the following:
- listen for messages publishing tempreature and humidity
- perform calculation
- enrich message with calculated value
code for calculation in JavaScript:
var tempC = msg.payload.temperature;
var humidRel = msg.payload.humidity;
// Konstanten
var molekulargewicht = 18.016; // des Wasserdampfes in kg/kmol
var gaskonstante = 8214.3; // in J/(kmol*K)
var tempK = tempC + 273.15;
var a, b;
if (tempC >= 0) {
a = 7.5;
b = 237.3;
} else {
a = 7.6;
b = 240.7;
}
// Sättigungsdampfdruck (hPa)
var saettigungsDampfDruck = 6.1078 * Math.pow(10, (a * tempC) / (b + tempC));
// Dampfdruck (hPa)
var dampfDruck = saettigungsDampfDruck * (humidRel / 100);
// Wasserdampfdichte bzw. absolute Feuchte (g/m3)
var humidAbs = Math.pow(10,5) * molekulargewicht / gaskonstante * dampfDruck / tempK;
// v-Parameter
var v = Math.log10(dampfDruck / 6.1078);
// Taupunkttemperatur (°C)
var dewpointC = (b * v) / (a - v);
Any help would be apreciated!
I manged to build a working extension. Only part missing is the enriching of the message published by Z2M via MQTT:
[ok] listen for messages publishing tempreature and humidity [ok] perform calculation [ ] enrich message with calculated value
Is this the correct binding to "intercept" and enrich a MQTT-Message? How is this done? PS: I did not find any class diagram or sth similar - getting through all this classes was quite hard ;)
class DewpointCalculator {
constructor(zigbee, mqtt, state, publishEntityState, eventBus, settings, logger) {
this.eventBus = eventBus;
this.logger = logger;
this.eventBus.on('stateChange', this.onStateChange.bind(this), this.constructor.name);
logger.info('Loaded DewpointCalculator');
}
async onStateChange(data) {
const { entity, update } = data;
if ((data.to.hasOwnProperty('temperature')) & (data.to.hasOwnProperty('humidity'))) {
if (!data.to.hasOwnProperty('dewpoint')) {
// this should be added to the mqtt-message published
this.logger.info(this.calculateDewpoint(data.to['temperature'], data.to['humidity']));
}
}
}
calculateDewpoint(tempC, humidRel) {
var molecularWeight = 18.016; // of water vapor in kg/kmol
var gasConstant = 8214.3; // in J/(kmol*K)
var tempK = tempC + 273.15;
var a, b;
if (tempC >= 0) {
a = 7.5;
b = 237.3;
} else {
a = 7.6;
b = 240.7;
}
// saturation vapor pressure (hPa)
var saturationVaporPressure=6.1078*Math.pow(10,(a*tempC)/(b+tempC));
// vapor pressure (hPa)
var vaporPressure = saturationVaporPressure*(humidRel/100);
// Wasserdampfdichte bzw. absolute Feuchte (g/m3)
var humidAbs = Math.pow(10,5)*molecularWeight/gasConstant*vaporPressure/tempK;
// v-Parameter
var v = Math.log10(vaporPressure/6.1078);
// Taupunkttemperatur (°C)
var dewpointC = (b*v)/(a-v);
return(dewpointC.toFixed(2));
}
async onMQTTMessage(topic, message) {
// console.log({topic, message});
}
async stop() {
this.eventBus.removeListeners(this.constructor.name);
this.logger.info('Unloaded DewpointCalculator');
}
}
module.exports = DewpointCalculator;
This seems interesting, but I can't come up with a way to inject this either.
I don't think there is a way to modify the message before z2m publishes it to include the info. You could publish it on a separate topic perhaps.
facepalm it is THAT easy...
just add a new property to the data object...
data.to['dewpoint'] = +this.calculateDewpoint(data.to['temperature'], data.to['humidity']);
class DewpointCalculator {
constructor(
zigbee,
mqtt,
state,
publishEntityState,
eventBus,
enableDisableExtension,
restartCallback,
addExtension,
settings,
logger,
) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishEntityState = publishEntityState;
this.eventBus = eventBus;
this.enableDisableExtension = enableDisableExtension;
this.restartCallback = restartCallback;
this.addExtension = addExtension;
this.settings = settings;
this.logger = logger;
this.logger.info('Loaded DewpointCalculator');
// this.mqttBaseTopic = this.settings.get().mqtt.base_topic;
}
/**
* Called when the extension starts (on Zigbee2MQTT startup, or when the extension is saved at runtime)
*/
start() {
this.logger.info('DewpointCalculator - start');
// all possible events can be seen here: https://github.com/Koenkk/zigbee2mqtt/blob/master/lib/eventBus.ts
this.eventBus.onStateChange(this, this.onStateChange.bind(this));
// this.mqtt.publish('DewpointCalculator/state', 'running');
// this.logger.info('DewpointCalculator - started');
}
/**
* Called when the extension stops (on Zigbee2MQTT shutdown, or when the extension is saved/removed at runtime)
*/
stop() {
this.logger.info('DewpointCalculator - stop');
// unload listener
this.eventBus.removeListeners(this);
// this.mqtt.publish('DewpointCalculator/state', 'stop');
// this.logger.info('DewpointCalculator - stopped');
}
async onStateChange(data) {
// see typing (properties) here: https://github.com/Koenkk/zigbee2mqtt/blob/master/lib/types/types.d.ts => namespace eventdata
const { entity, update } = data;
if ((data.to.hasOwnProperty('temperature')) & (data.to.hasOwnProperty('humidity'))) {
if (!data.to.hasOwnProperty('dewpoint')) {
// add custom property called "dewpoint" beeing calculated by method calculateDewpoint()
data.to['dewpoint'] = +this.calculateDewpoint(data.to['temperature'], data.to['humidity']);
}
}
}
calculateDewpoint(tempC, humidRel) {
var molecularWeight = 18.016; // of water vapor in kg/kmol
var gasConstant = 8214.3; // in J/(kmol*K)
var tempK = tempC + 273.15;
var a, b;
if (tempC >= 0) {
a = 7.5;
b = 237.3;
} else {
a = 7.6;
b = 240.7;
}
// saturation vapor pressure (hPa)
var saturationVaporPressure=6.1078*Math.pow(10,(a*tempC)/(b+tempC));
// vapor pressure (hPa)
var vaporPressure = saturationVaporPressure*(humidRel/100);
// Wasserdampfdichte bzw. absolute Feuchte (g/m3)
var humidAbs = Math.pow(10,5)*molecularWeight/gasConstant*vaporPressure/tempK;
// v-Parameter
var v = Math.log10(vaporPressure/6.1078);
// Taupunkttemperatur (°C)
var dewpointC = (b*v)/(a-v);
return(+dewpointC.toFixed(2));
}
async onMQTTMessage(topic, message) {
// console.log({topic, message});
}
}
// eslint-disable-next-line no-undef
module.exports = DewpointCalculator;
quickly added a https://github.com/Koenkk/zigbee2mqtt-user-extensions/pull/17 so will close this here.
@sjorge: do you know a way to make HomeAssistant aware of the newly introduced value as a sensor?
The sensor configuration is published in separte topics:
One way may be manipulating these topics, but that wouldn't be a "correct" way. So are there any calls on a device (which is part of the used hooks parameters) to add this value "official" to the device?