bool CDavisLoggerSerial::HandleLoopData(const unsigned char *data, size_t len)
{
	const uint8_t *pData=data+1;

#ifndef DEBUG_DAVIS
	if (len!=100)
		return false;

	if (
		(data[1]!='L')||
		(data[2]!='O')||
		(data[3]!='O')||
		(data[96]!=0x0a)||
		(data[97]!=0x0d)
		)
		return false;
	//bool bIsRevA = (data[4]=='P');
#else
//	FILE *fOut=fopen("davisrob.bin","wb+");
//	fwrite(data,1,len,fOut);
//	fclose(fOut);
	unsigned char szBuffer[200];
	FILE *fIn=fopen("E:\\davis2.bin","rb+");
	//FILE *fIn=fopen("davisrob.bin","rb+");
	fread(&szBuffer,1,100,fIn);
	fclose(fIn);
	pData=szBuffer+1;
	bool bIsRevA(szBuffer[4]=='P');
#endif

	RBUF tsen;
	memset(&tsen,0,sizeof(RBUF));


	unsigned char tempIdx=1;

	bool bBaroValid=false;
	float BaroMeter=0;
	bool bInsideTemperatureValid=false;
	float InsideTemperature=0;
	bool bInsideHumidityValid=false;
	int InsideHumidity=0;
	bool bOutsideTemperatureValid=false;
	float OutsideTemperature=0;
	bool bOutsideHumidityValid=false;
	int OutsideHumidity=0;

	bool bWindDirectionValid=false;
	int WindDirection=0;

	bool bWindSpeedValid=false;
	float WindSpeed=0;
	bool bWindSpeedAVR10Valid=false;
	float WindSpeedAVR10=0;

	bool bUVValid=false;
	float UV=0;

	//Barometer
	if ((pData[7]!=0xFF)&&(pData[8]!=0xFF))
	{
		bBaroValid=true;
		BaroMeter=((unsigned int)((pData[8] << 8) | pData[7])) / 29.53f; //in hPa
	}
	//Inside Temperature
	if ((pData[9]!=0xFF)||(pData[10]!=0x7F))
	{
		bInsideTemperatureValid=true;
		InsideTemperature=((unsigned int)((pData[10] << 8) | pData[9])) / 10.f;
		InsideTemperature = (InsideTemperature - 32.0f) * 5.0f / 9.0f;
	}
	//Inside Humidity
	if (pData[11]!=0xFF)
	{
		InsideHumidity=pData[11];
		if (InsideHumidity<101)
			bInsideHumidityValid=true;
	}

	if (bBaroValid&&bInsideTemperatureValid&&bInsideHumidityValid)
	{
		uint8_t forecastitem = pData[89];
		int forecast = 0;

		if ((forecastitem & 0x01) == 0x01)
			forecast = wsbaroforcast_rain;
		else if ((forecastitem & 0x02) == 0x02)
			forecast = wsbaroforcast_cloudy;
		else if ((forecastitem & 0x04) == 0x04)
			forecast = wsbaroforcast_some_clouds;
		else if ((forecastitem & 0x08) == 0x08)
			forecast = wsbaroforcast_sunny;
		else if ((forecastitem & 0x10) == 0x10)
			forecast = wsbaroforcast_snow;

		SendTempHumBaroSensorFloat(tempIdx++, 255, InsideTemperature, InsideHumidity, BaroMeter, forecast, "THB");
	}

	//Outside Temperature
	if ((pData[12]!=0xFF)||(pData[13]!=0x7F))
	{
		bOutsideTemperatureValid=true;
		OutsideTemperature=((unsigned int)((pData[13] << 8) | pData[12])) / 10.f;

		OutsideTemperature = (OutsideTemperature - 32.0f) * 5.0f / 9.0f;
	}
	//Outside Humidity
	if (pData[33]!=0xFF)
	{
		OutsideHumidity=pData[33];
		if (OutsideHumidity<101)
			bOutsideHumidityValid=true;
	}
	if (bOutsideTemperatureValid||bOutsideHumidityValid)
	{
		if ((bOutsideTemperatureValid)&&(bOutsideHumidityValid))
		{
			//Temp+hum
			SendTempHumSensor(tempIdx++, 255, OutsideTemperature, OutsideHumidity,"Outside TempHum");
		}
		else if (bOutsideTemperatureValid)
		{
			//Temp
			SendTempSensor(tempIdx++, 255, OutsideTemperature, "Outside Temp");
		}
		else if (bOutsideHumidityValid)
		{
			//hum
			SendHumiditySensor(tempIdx++, 255, OutsideHumidity, "Outside Humidity");
		}
	}

	tempIdx=10;
	//Add Extra Temp/Hum Sensors
	int iTmp;
	for (int iTmp=0; iTmp<7; iTmp++)
	{
		bool bTempValid=false;
		bool bHumValid=false;
		float temp=0;
		uint8_t hum=0;

		if (pData[18+iTmp]!=0xFF)
		{
			bTempValid=true;
			temp=pData[18+iTmp]-90.0f;
			temp = (temp - 32.0f) * 5.0f / 9.0f;
		}
		if (pData[34+iTmp]!=0xFF)
		{
			bHumValid=true;
			hum=pData[34+iTmp];
		}
		if ((bTempValid)&&(bHumValid))
		{
			//Temp+hum
			SendTempHumSensor(tempIdx++, 255, temp, hum, "Extra TempHum");
		}
		else if (bTempValid)
		{
			//Temp
			SendTempSensor(tempIdx++, 255, temp, "Extra Temp");
		}
		else if (bHumValid)
		{
			//hum
			SendHumiditySensor(tempIdx++, 255, hum, "Extra Humidity");
		}
	}

	tempIdx=20;
	//Add Extra Soil Temp Sensors
	for (iTmp=0; iTmp<4; iTmp++)
	{
		bool bTempValid=false;
		float temp=0;

		if (pData[25+iTmp]!=0xFF)
		{
			bTempValid=true;
			temp=pData[25+iTmp]-90.0f;
			temp = (temp - 32.0f) * 5.0f / 9.0f;
		}
		if (bTempValid)
		{
			SendTempSensor(tempIdx++, 255, temp, "Soil Temp");
		}
	}

	tempIdx=30;
	//Add Extra Leaf Temp Sensors
	for (iTmp=0; iTmp<4; iTmp++)
	{
		bool bTempValid=false;
		float temp=0;

		if (pData[29+iTmp]!=0xFF)
		{
			bTempValid=true;
			temp=pData[29+iTmp]-90.0f;
			temp = (temp - 32.0f) * 5.0f / 9.0f;
		}
		if (bTempValid)
		{
			SendTempSensor(tempIdx++, 255, temp, "Leaf Temp");
		}
	}

	//Wind Speed
	if (pData[14]!=0xFF)
	{
		bWindSpeedValid=true;
		WindSpeed=(pData[14])*(4.0f/9.0f);
	}
	//Wind Speed AVR 10 minutes
	if (pData[15]!=0xFF)
	{
		bWindSpeedAVR10Valid=true;
		WindSpeedAVR10=(pData[15])*(4.0f/9.0f);
	}
	//Wind Direction
	if ((pData[16]!=0xFF)&&(pData[17]!=0x7F))
	{
		bWindDirectionValid=true;
		WindDirection=((unsigned int)((pData[17] << 8) | pData[16]));
	}

	if ((bWindSpeedValid)&&(bWindDirectionValid))
	{
		memset(&tsen,0,sizeof(RBUF));
		tsen.WIND.packetlength=sizeof(tsen.WIND)-1;
		tsen.WIND.packettype=pTypeWIND;
		tsen.WIND.subtype=sTypeWINDNoTemp;
		tsen.WIND.battery_level=9;
		tsen.WIND.rssi=12;
		tsen.WIND.id1=0;
		tsen.WIND.id2=1;

		int aw=round(WindDirection);
		tsen.WIND.directionh=(BYTE)(aw/256);
		aw-=(tsen.WIND.directionh*256);
		tsen.WIND.directionl=(BYTE)(aw);

		tsen.WIND.av_speedh=0;
		tsen.WIND.av_speedl=0;
		int sw=round(WindSpeed*10.0f);
		tsen.WIND.av_speedh=(BYTE)(sw/256);
		sw-=(tsen.WIND.av_speedh*256);
		tsen.WIND.av_speedl=(BYTE)(sw);

		tsen.WIND.gusth=0;
		tsen.WIND.gustl=0;

		//this is not correct, why no wind temperature? and only chill?
		tsen.WIND.chillh=0;
		tsen.WIND.chilll=0;
		tsen.WIND.temperatureh=0;
		tsen.WIND.temperaturel=0;
		if (bOutsideTemperatureValid)
		{
			tsen.WIND.tempsign=(OutsideTemperature>=0)?0:1;
			tsen.WIND.chillsign=(OutsideTemperature>=0)?0:1;
			int at10=round(abs(OutsideTemperature*10.0f));
			tsen.WIND.temperatureh=(BYTE)(at10/256);
			tsen.WIND.chillh=(BYTE)(at10/256);
			at10-=(tsen.WIND.chillh*256);
			tsen.WIND.temperaturel=(BYTE)(at10);
			tsen.WIND.chilll=(BYTE)(at10);
		}

		sDecodeRXMessage(this, (const unsigned char *)&tsen.WIND, NULL, 255);
	}

	//UV
	if (pData[43]!=0xFF)
	{
		UV=(pData[43])/10.0f;
		if (UV<100)
			bUVValid=true;
	}
	if (bUVValid)
	{
		RBUF tsen;
		memset(&tsen,0,sizeof(RBUF));
		tsen.UV.packetlength=sizeof(tsen.UV)-1;
		tsen.UV.packettype=pTypeUV;
		tsen.UV.subtype=sTypeUV1;
		tsen.UV.battery_level=9;
		tsen.UV.rssi=12;
		tsen.UV.id1=0;
		tsen.UV.id2=1;

		tsen.UV.uv=(BYTE)round(UV*10);
		sDecodeRXMessage(this, (const unsigned char *)&tsen.UV, NULL, 255);
	}
	
	//Rain Rate
	if ((pData[41]!=0xFF)&&(pData[42]!=0xFF))
	{
		float rainRate=((unsigned int)((pData[42] << 8) | pData[41])) / 100.0f; //inches
		rainRate*=25.4f; //mm
	}
	//Rain Day
	if ((pData[50]!=0xFF)&&(pData[51]!=0xFF))
	{
		float rainDay=((unsigned int)((pData[51] << 8) | pData[50])) / 100.0f; //inches
		rainDay*=25.4f; //mm
	}
	//Rain Year
	if ((pData[54]!=0xFF)&&(pData[55]!=0xFF))
	{
		float rainYear=((unsigned int)((pData[55] << 8) | pData[54])) / 100.0f; //inches
		rainYear*=25.4f; //mm

		SendRainSensor(1, 255, rainYear, "Rain");
	}

	//Solar Radiation
	if ((pData[44]!=0xFF)&&(pData[45]!=0x7F))
	{
		unsigned int solarRadiation=((unsigned int)((pData[45] << 8) | pData[44]));//Watt/M2
		_tGeneralDevice gdevice;
		gdevice.subtype=sTypeSolarRadiation;
		gdevice.floatval1=float(solarRadiation);
		sDecodeRXMessage(this, (const unsigned char *)&gdevice, NULL, 255);

	}

	//Soil Moistures
	for (int iMoister=0; iMoister<4; iMoister++)
	{
		if (pData[62+iMoister]!=0xFF)
		{
			int moister=pData[62+iMoister];
			SendMoistureSensor(1 + iMoister, 255, moister, "Moisture");
		}
	}

	//Leaf Wetness
	for (int iLeaf=0; iLeaf<4; iLeaf++)
	{
		if (pData[66+iLeaf]!=0xFF)
		{
			int leaf_wetness=pData[66+iLeaf];

			_tGeneralDevice gdevice;
			gdevice.subtype=sTypeLeafWetness;
			gdevice.intval1=leaf_wetness;
			gdevice.id=1+iLeaf;
			sDecodeRXMessage(this, (const unsigned char *)&gdevice, NULL, 255);
		}
	}

	return true;
}
Beispiel #2
0
void MySensorsBase::SendSensor2Domoticz(_tMySensorNode *pNode, _tMySensorChild *pChild, const _eSetType vType)
{
	m_iLastSendNodeBatteryValue = 255;
	if (pChild->hasBattery)
	{
		m_iLastSendNodeBatteryValue = pChild->batValue;
	}
	int cNode = (pChild->nodeID << 8) | pChild->childID;
	int intValue;
	float floatValue;
	std::string stringValue;

	switch (vType)
	{
	case V_TEMP:
	{
		float Temp = 0;
		pChild->GetValue(V_TEMP, Temp);
		_tMySensorChild *pChildHum = FindChildWithValueType(pChild->nodeID, V_HUM);
		_tMySensorChild *pChildBaro = FindChildWithValueType(pChild->nodeID, V_PRESSURE);
		if (pChildHum && pChildBaro)
		{
			int Humidity;
			float Baro;
			bool bHaveHumidity = pChildHum->GetValue(V_HUM, Humidity);
			bool bHaveBaro = pChildBaro->GetValue(V_PRESSURE, Baro);
			if (bHaveHumidity && bHaveBaro)
			{
				int forecast = bmpbaroforecast_unknown;
				_tMySensorChild *pSensorForecast = FindChildWithValueType(pChild->nodeID, V_FORECAST);
				if (pSensorForecast)
				{
					pSensorForecast->GetValue(V_FORECAST, forecast);
				}
				if (forecast == bmpbaroforecast_cloudy)
				{
					if (Baro < 1010)
						forecast = bmpbaroforecast_rain;
				}

				//We are using the TempHumBaro Float type now, convert the forecast
				int nforecast = wsbaroforcast_some_clouds;
				if (Baro <= 980)
					nforecast = wsbaroforcast_heavy_rain;
				else if (Baro <= 995)
				{
					if (Temp > 1)
						nforecast = wsbaroforcast_rain;
					else
						nforecast = wsbaroforcast_snow;
					break;
				}
				else if (Baro >= 1029)
					nforecast = wsbaroforcast_sunny;
				switch (forecast)
				{
				case bmpbaroforecast_sunny:
					nforecast = wsbaroforcast_sunny;
					break;
				case bmpbaroforecast_cloudy:
					nforecast = wsbaroforcast_cloudy;
					break;
				case bmpbaroforecast_thunderstorm:
					nforecast = wsbaroforcast_heavy_rain;
					break;
				case bmpbaroforecast_rain:
					if (Temp>1)
						nforecast = wsbaroforcast_rain;
					else
						nforecast = wsbaroforcast_snow;
					break;
				}
				SendTempHumBaroSensorFloat(cNode, pChild->batValue, Temp, Humidity, Baro, nforecast, (!pChild->childName.empty()) ? pChild->childName : "TempHumBaro");
			}
		}
		else if (pChildHum) {
			int Humidity;
			bool bHaveHumidity = pChildHum->GetValue(V_HUM, Humidity);
			if (bHaveHumidity)
			{
				SendTempHumSensor(cNode, pChild->batValue, Temp, Humidity, (!pChild->childName.empty()) ? pChild->childName : "TempHum");
			}
		}
		else
		{
			SendTempSensor(cNode, pChild->batValue, Temp, (!pChild->childName.empty()) ? pChild->childName : "Temp");
		}
	}
	break;
	case V_HUM:
	{
		_tMySensorChild *pChildTemp = FindChildWithValueType(pChild->nodeID, V_TEMP);
		_tMySensorChild *pChildBaro = FindChildWithValueType(pChild->nodeID, V_PRESSURE);
		int forecast = bmpbaroforecast_unknown;
		_tMySensorChild *pSensorForecast = FindChildWithValueType(pChild->nodeID, V_FORECAST);
		if (pSensorForecast)
		{
			pSensorForecast->GetValue(V_FORECAST, forecast);
		}
		if (forecast == bmpbaroforecast_cloudy)
		{
			if (pChildBaro)
			{
				float Baro;
				if (pChildBaro->GetValue(V_PRESSURE, Baro))
				{
					if (Baro < 1010)
						forecast = bmpbaroforecast_rain;
				}
			}
		}
		float Temp;
		float Baro;
		int Humidity;
		pChild->GetValue(V_HUM, Humidity);
		if (pChildTemp && pChildBaro)
		{
			bool bHaveTemp = pChildTemp->GetValue(V_TEMP, Temp);
			bool bHaveBaro = pChildBaro->GetValue(V_PRESSURE, Baro);
			if (bHaveTemp && bHaveBaro)
			{
				cNode = (pChildTemp->nodeID << 8) | pChildTemp->childID;

				//We are using the TempHumBaro Float type now, convert the forecast
				int nforecast = wsbaroforcast_some_clouds;
				if (Baro <= 980)
					nforecast = wsbaroforcast_heavy_rain;
				else if (Baro <= 995)
				{
					if (Temp > 1)
						nforecast = wsbaroforcast_rain;
					else
						nforecast = wsbaroforcast_snow;
					break;
				}
				else if (Baro >= 1029)
					nforecast = wsbaroforcast_sunny;
				switch (forecast)
				{
				case bmpbaroforecast_sunny:
					nforecast = wsbaroforcast_sunny;
					break;
				case bmpbaroforecast_cloudy:
					nforecast = wsbaroforcast_cloudy;
					break;
				case bmpbaroforecast_thunderstorm:
					nforecast = wsbaroforcast_heavy_rain;
					break;
				case bmpbaroforecast_rain:
					if (Temp > 1)
						nforecast = wsbaroforcast_rain;
					else
						nforecast = wsbaroforcast_snow;
					break;
				}

				SendTempHumBaroSensorFloat(cNode, pChildTemp->batValue, Temp, Humidity, Baro, nforecast, (!pChild->childName.empty()) ? pChild->childName : "TempHumBaro");
			}
		}
		else if (pChildTemp) {
			bool bHaveTemp = pChildTemp->GetValue(V_TEMP, Temp);
			if (bHaveTemp)
			{
				cNode = (pChildTemp->nodeID << 8) | pChildTemp->childID;
				SendTempHumSensor(cNode, pChildTemp->batValue, Temp, Humidity, (!pChild->childName.empty()) ? pChild->childName : "TempHum");
			}
		}
		else
		{
			SendHumiditySensor(cNode, pChild->batValue, Humidity);
		}
	}
	break;
	case V_PRESSURE:
	{
		float Baro;
		pChild->GetValue(V_PRESSURE, Baro);
		_tMySensorChild *pSensorTemp = FindChildWithValueType(pChild->nodeID, V_TEMP);
		_tMySensorChild *pSensorHum = FindChildWithValueType(pChild->nodeID, V_HUM);
		int forecast = bmpbaroforecast_unknown;
		_tMySensorChild *pSensorForecast = FindChildWithValueType(pChild->nodeID, V_FORECAST);
		if (pSensorForecast)
		{
			pSensorForecast->GetValue(V_FORECAST, forecast);
		}
		if (forecast == bmpbaroforecast_cloudy)
		{
			if (Baro < 1010)
				forecast = bmpbaroforecast_rain;
		}
		if (pSensorTemp && pSensorHum)
		{
			float Temp;
			int Humidity;
			bool bHaveTemp = pSensorTemp->GetValue(V_TEMP, Temp);
			bool bHaveHumidity = pSensorHum->GetValue(V_HUM, Humidity);

			if (bHaveTemp && bHaveHumidity)
			{
				cNode = (pSensorTemp->nodeID << 8) | pSensorTemp->childID;
				//We are using the TempHumBaro Float type now, convert the forecast
				int nforecast = wsbaroforcast_some_clouds;
				if (Baro <= 980)
					nforecast = wsbaroforcast_heavy_rain;
				else if (Baro <= 995)
				{
					if (Temp > 1)
						nforecast = wsbaroforcast_rain;
					else
						nforecast = wsbaroforcast_snow;
					break;
				}
				else if (Baro >= 1029)
					nforecast = wsbaroforcast_sunny;
				switch (forecast)
				{
				case bmpbaroforecast_sunny:
					nforecast = wsbaroforcast_sunny;
					break;
				case bmpbaroforecast_cloudy:
					nforecast = wsbaroforcast_cloudy;
					break;
				case bmpbaroforecast_thunderstorm:
					nforecast = wsbaroforcast_heavy_rain;
					break;
				case bmpbaroforecast_rain:
					if (Temp > 1)
						nforecast = wsbaroforcast_rain;
					else
						nforecast = wsbaroforcast_snow;
					break;
				}
				SendTempHumBaroSensorFloat(cNode, pSensorTemp->batValue, Temp, Humidity, Baro, nforecast, (!pChild->childName.empty()) ? pChild->childName : "TempHumBaro");
			}
		}
		else
			SendBaroSensor(pChild->nodeID, pChild->childID, pChild->batValue, Baro, forecast);
	}
	break;
	case V_TRIPPED:
		//	Tripped status of a security sensor. 1 = Tripped, 0 = Untripped
		if (pChild->GetValue(vType, intValue))
			UpdateSwitch(pChild->nodeID, pChild->childID, (intValue == 1), 100, "Security Sensor");
		break;
	case V_ARMED:
		//Armed status of a security sensor. 1 = Armed, 0 = Bypassed
		if (pChild->GetValue(vType, intValue))
			UpdateSwitch(pChild->nodeID, pChild->childID, (intValue == 1), 100, "Security Sensor");
		break;
	case V_LOCK_STATUS:
		//Lock status. 1 = Locked, 0 = Unlocked
		if (pChild->GetValue(vType, intValue))
			UpdateSwitch(pChild->nodeID, pChild->childID, (intValue == 1), 100, "Lock Sensor");
		break;
	case V_STATUS:
		//	Light status. 0 = off 1 = on
		if (pChild->GetValue(vType, intValue))
			UpdateSwitch(pChild->nodeID, pChild->childID, (intValue != 0), 100, "Light");
		break;
	case V_SCENE_ON:
		if (pChild->GetValue(vType, intValue))
			UpdateSwitch(pChild->nodeID, pChild->childID + intValue, true, 100, "Scene");
		break;
	case V_SCENE_OFF:
		if (pChild->GetValue(vType, intValue))
			UpdateSwitch(pChild->nodeID, pChild->childID + intValue, false, 100, "Scene");
		break;
	case V_PERCENTAGE:
		//	Dimmer value. 0 - 100 %
		if (pChild->GetValue(vType, intValue))
		{
			int level = intValue;
			UpdateSwitch(pChild->nodeID, pChild->childID, (level != 0), level, "Light");
		}
		break;
	case V_RGB:
		//RRGGBB
		if (pChild->GetValue(vType, intValue))
			SendRGBWSwitch(pChild->nodeID, pChild->childID, pChild->batValue, intValue, false, (!pChild->childName.empty()) ? pChild->childName : "RGB Light");
		break;
	case V_RGBW:
		//RRGGBBWW
		if (pChild->GetValue(vType, intValue))
			SendRGBWSwitch(pChild->nodeID, pChild->childID, pChild->batValue, intValue, true, (!pChild->childName.empty()) ? pChild->childName : "RGBW Light");
		break;
	case V_UP:
	case V_DOWN:
	case V_STOP:
		if (pChild->GetValue(vType, intValue))
			SendBlindSensor(pChild->nodeID, pChild->childID, pChild->batValue, intValue, (!pChild->childName.empty()) ? pChild->childName : "Blinds/Window");
		break;
	case V_LIGHT_LEVEL:
		if (pChild->GetValue(vType, floatValue))
		{
			_tLightMeter lmeter;
			lmeter.id1 = 0;
			lmeter.id2 = 0;
			lmeter.id3 = 0;
			lmeter.id4 = pChild->nodeID;
			lmeter.dunit = pChild->childID;
			lmeter.fLux = floatValue;
			lmeter.battery_level = pChild->batValue;
			if (pChild->hasBattery)
				lmeter.battery_level = pChild->batValue;
			sDecodeRXMessage(this, (const unsigned char *)&lmeter);
		}
		break;
	case V_LEVEL:
		if ((pChild->presType == S_DUST)|| (pChild->presType == S_AIR_QUALITY))
		{
			if (pChild->GetValue(vType, intValue))
			{
				_tAirQualityMeter meter;
				meter.len = sizeof(_tAirQualityMeter) - 1;
				meter.type = pTypeAirQuality;
				meter.subtype = sTypeVoltcraft;
				meter.airquality = intValue;
				meter.id1 = pChild->nodeID;
				meter.id2 = pChild->childID;
				sDecodeRXMessage(this, (const unsigned char *)&meter);
			}
		}
		else if (pChild->presType == S_LIGHT_LEVEL)
		{
			if (pChild->GetValue(vType, intValue))
			{
				_tLightMeter lmeter;
				lmeter.id1 = 0;
				lmeter.id2 = 0;
				lmeter.id3 = 0;
				lmeter.id4 = pChild->nodeID;
				lmeter.dunit = pChild->childID;
				lmeter.fLux = (float)intValue;
				lmeter.battery_level = pChild->batValue;
				if (pChild->hasBattery)
					lmeter.battery_level = pChild->batValue;
				sDecodeRXMessage(this, (const unsigned char *)&lmeter);
			}
		}
		else if (pChild->presType == S_SOUND)
		{
			if (pChild->GetValue(vType, intValue))
				SendSoundSensor(cNode, pChild->batValue, intValue, (!pChild->childName.empty()) ? pChild->childName : "Sound Level");
		}
		else if (pChild->presType == S_MOISTURE)
		{
			if (pChild->GetValue(vType, intValue))
			{
				_tGeneralDevice gdevice;
				gdevice.subtype = sTypeSoilMoisture;
				gdevice.intval1 = intValue;
				gdevice.id = pChild->nodeID;
				sDecodeRXMessage(this, (const unsigned char *)&gdevice);
			}
		}
		break;
	case V_RAIN:
		if (pChild->GetValue(vType, floatValue))
			SendRainSensor(cNode, pChild->batValue, floatValue, (!pChild->childName.empty()) ? pChild->childName : "Rain");
		break;
	case V_WATT:
		{
			if (pChild->GetValue(vType, floatValue))
			{
				_tMySensorChild *pSensorKwh = pNode->FindChildWithValueType(pChild->childID, V_KWH);// FindChildWithValueType(pChild->nodeID, V_KWH);
				if (pSensorKwh) {
					float Kwh;
					if (pSensorKwh->GetValue(V_KWH, Kwh))
						SendKwhMeter(pSensorKwh->nodeID, pSensorKwh->childID, pSensorKwh->batValue, floatValue / 1000.0f, Kwh, (!pChild->childName.empty()) ? pChild->childName : "Meter");
				}
				else {
					SendWattMeter(pChild->nodeID, pChild->childID, pChild->batValue, floatValue, (!pChild->childName.empty()) ? pChild->childName : "Usage");
				}
			}
		}
		break;
	case V_KWH:
		if (pChild->GetValue(vType, floatValue))
		{
			_tMySensorChild *pSensorWatt = pNode->FindChildWithValueType(pChild->childID, V_WATT);// FindChildWithValueType(pChild->nodeID, V_WATT);
			if (pSensorWatt) {
				float Watt;
				if (pSensorWatt->GetValue(V_WATT, Watt))
					SendKwhMeter(pChild->nodeID, pChild->childID, pChild->batValue, Watt / 1000.0f, floatValue, (!pChild->childName.empty()) ? pChild->childName : "Meter");
			}
			else {
				SendKwhMeter(pChild->nodeID, pChild->childID, pChild->batValue, 0, floatValue, (!pChild->childName.empty()) ? pChild->childName : "Meter");
			}
		}
		break;
	case V_DISTANCE:
		if (pChild->GetValue(vType, floatValue))
			SendDistanceSensor(pChild->nodeID, pChild->childID, pChild->batValue, floatValue);
		break;
	case V_FLOW:
		//Flow of water in meter (for now send as a percentage sensor)
		if (pChild->GetValue(vType, floatValue))
			SendPercentageSensor(pChild->nodeID, pChild->childID, pChild->batValue, floatValue, (!pChild->childName.empty()) ? pChild->childName : "Water Flow");
		break;
	case V_VOLUME:
		//Water Volume
		if (pChild->GetValue(vType, floatValue))
			SendMeterSensor(pChild->nodeID, pChild->childID, pChild->batValue, floatValue, (!pChild->childName.empty()) ? pChild->childName : "Water");
		break;
	case V_VOLTAGE:
		if (pChild->GetValue(vType, floatValue))
			SendVoltageSensor(pChild->nodeID, pChild->childID, pChild->batValue, floatValue, (!pChild->childName.empty()) ? pChild->childName : "Voltage");
		break;
	case V_UV:
		if (pChild->GetValue(vType, floatValue))
			SendUVSensor(pChild->nodeID, pChild->childID, pChild->batValue, floatValue);
		break;
	case V_IMPEDANCE:
		if (pChild->GetValue(vType, floatValue))
			SendPercentageSensor(pChild->nodeID, pChild->childID, pChild->batValue, floatValue, (!pChild->childName.empty()) ? pChild->childName : "Impedance");
		break;
	case V_WEIGHT:
		if (pChild->GetValue(vType, floatValue))
		{
			while (1 == 0);
		}
		break;
	case V_CURRENT:
		if (pChild->GetValue(vType, floatValue))
			SendCurrentSensor(cNode, pChild->batValue, floatValue, 0, 0, (!pChild->childName.empty()) ? pChild->childName : "Current");
		break;
	case V_FORECAST:
		if (pChild->GetValue(vType, intValue))
		{
			_tMySensorChild *pSensorBaro = FindChildWithValueType(pChild->nodeID, V_PRESSURE);
			if (pSensorBaro)
			{
				float Baro;
				if (pSensorBaro->GetValue(V_PRESSURE, Baro))
				{
					int forecast = intValue;
					if (forecast == bmpbaroforecast_cloudy)
					{
						if (Baro < 1010)
							forecast = bmpbaroforecast_rain;
					}
					SendBaroSensor(pSensorBaro->nodeID, pSensorBaro->childID, pSensorBaro->batValue, Baro, forecast);
				}
			}
			else
			{
				if (pChild->GetValue(V_FORECAST, stringValue))
				{
					std::stringstream sstr;
					sstr << pChild->nodeID;
					std::string devname = (!pChild->childName.empty()) ? pChild->childName : "Forecast";
					m_sql.UpdateValue(m_HwdID, sstr.str().c_str(), pChild->childID, pTypeGeneral, sTypeTextStatus, 12, pChild->batValue, 0, stringValue.c_str(), devname);
				}
			}
		}
		break;
	case V_WIND:
	case V_GUST:
	case V_DIRECTION:
		MakeAndSendWindSensor(pChild->nodeID, (!pChild->childName.empty()) ? pChild->childName : "Wind");
		break;
	case V_HVAC_SETPOINT_HEAT:
		if (pChild->GetValue(vType, floatValue))
		{
			SendSetPointSensor(pNode->nodeID, pChild->childID, floatValue, (!pChild->childName.empty()) ? pChild->childName : "Heater Setpoint");
		}
		break;
	}
}