mirror of
https://github.com/ckaczor/WeatherService.git
synced 2026-01-13 17:23:11 -05:00
Initial commit
This commit is contained in:
267
Devices/DeviceBase.cs
Normal file
267
Devices/DeviceBase.cs
Normal file
@@ -0,0 +1,267 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using OneWireAPI;
|
||||
using System.Collections.Generic;
|
||||
using WeatherService.Data;
|
||||
using WeatherService.Values;
|
||||
|
||||
namespace WeatherService.Devices
|
||||
{
|
||||
#region Enumerations
|
||||
|
||||
[DataContract]
|
||||
public enum DeviceType
|
||||
{
|
||||
[EnumMember]
|
||||
None,
|
||||
|
||||
[EnumMember]
|
||||
Temperature,
|
||||
|
||||
[EnumMember]
|
||||
Pressure,
|
||||
|
||||
[EnumMember]
|
||||
Humidity,
|
||||
|
||||
[EnumMember]
|
||||
WindDirection,
|
||||
|
||||
[EnumMember]
|
||||
WindSpeed,
|
||||
|
||||
[EnumMember]
|
||||
Rain
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[DataContract]
|
||||
[KnownType(typeof(HumidityDevice))]
|
||||
[KnownType(typeof(PressureDevice))]
|
||||
[KnownType(typeof(RainDevice))]
|
||||
[KnownType(typeof(TemperatureDevice))]
|
||||
[KnownType(typeof(WindDirectionDevice))]
|
||||
[KnownType(typeof(WindSpeedDevice))]
|
||||
public class DeviceBase
|
||||
{
|
||||
#region Member variables
|
||||
|
||||
protected int _deviceId; // Device ID
|
||||
protected string _deviceAddress; // Device key
|
||||
protected Session _session; // The root session
|
||||
protected owDevice _device; // The one wire device
|
||||
protected DateTime _lastRead = DateTime.MinValue; // When was the last refresh?
|
||||
protected int _refreshFrequency; // How often should we refresh?
|
||||
protected Dictionary<WeatherValueType, Value> _valueList; // List of values
|
||||
protected string _displayName; // Device display name
|
||||
protected DeviceType _deviceType; // Type of device
|
||||
protected long _operationCount; // Number of operations
|
||||
protected long _errorCount; // Number of errors
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public DeviceBase(Session session, owDevice device, DeviceType deviceType)
|
||||
{
|
||||
// Initialize the value list
|
||||
_valueList = new Dictionary<WeatherValueType, Value>();
|
||||
|
||||
// Store properties of the device
|
||||
_deviceAddress = device.ID.Name;
|
||||
_deviceType = deviceType;
|
||||
_session = session;
|
||||
_device = device;
|
||||
|
||||
// Default the display name
|
||||
_displayName = device.ID.Name;
|
||||
|
||||
// Default the read interval
|
||||
if (Type == DeviceType.WindDirection || Type == DeviceType.WindSpeed)
|
||||
_refreshFrequency = 1;
|
||||
else
|
||||
_refreshFrequency = 120;
|
||||
|
||||
// Load device data
|
||||
bool bLoad = Load();
|
||||
|
||||
// If we couldn't load data then save the default data
|
||||
if (!bLoad)
|
||||
Save();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Save and load
|
||||
|
||||
internal bool Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get the device data from the database
|
||||
DeviceData deviceData = (from device in Database.DeviceTable where device.Address == _deviceAddress select device).First();
|
||||
|
||||
// Load the device data
|
||||
_deviceId = deviceData.Id;
|
||||
_displayName = deviceData.Name;
|
||||
_refreshFrequency = deviceData.ReadInterval;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool Save()
|
||||
{
|
||||
// Get the device data from the database
|
||||
DeviceData deviceData = (from device in Database.DeviceTable where device.Address == _deviceAddress select device).First();
|
||||
|
||||
// Save device data
|
||||
deviceData.Name = _displayName;
|
||||
deviceData.ReadInterval = _refreshFrequency;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal cache refresh logic
|
||||
|
||||
internal bool DoCacheRefresh()
|
||||
{
|
||||
switch (_refreshFrequency)
|
||||
{
|
||||
case -1:
|
||||
// Do not refresh this device
|
||||
return false;
|
||||
|
||||
case 0:
|
||||
// Refresh the device whenever possible
|
||||
RefreshCache();
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
if (_lastRead == DateTime.MinValue)
|
||||
{
|
||||
// If we have never refreshed before then do it now
|
||||
RefreshCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the time since the last refresh
|
||||
TimeSpan oTimeSpan = DateTime.Now - _lastRead;
|
||||
|
||||
// If it has been long enough then refresh the cache
|
||||
if (oTimeSpan.TotalSeconds >= _refreshFrequency)
|
||||
{
|
||||
RefreshCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual void RefreshCache()
|
||||
{
|
||||
// Store the current time
|
||||
_lastRead = DateTime.Now;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public properties
|
||||
|
||||
[DataMember]
|
||||
public int Id
|
||||
{
|
||||
get { return _deviceId; }
|
||||
set { _deviceId = value; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Address
|
||||
{
|
||||
get { return _deviceAddress; }
|
||||
set { _deviceAddress = value; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string DisplayName
|
||||
{
|
||||
get { return _displayName; }
|
||||
set { _displayName = value; }
|
||||
}
|
||||
|
||||
internal owDevice OneWireDevice
|
||||
{
|
||||
get { return _device; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public DateTime LastRead
|
||||
{
|
||||
get { return _lastRead; }
|
||||
set { _lastRead = value; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public long Operations
|
||||
{
|
||||
get { return _operationCount; }
|
||||
set { _operationCount = value; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public long Errors
|
||||
{
|
||||
get { return _errorCount; }
|
||||
set { _errorCount = value; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public DeviceType Type
|
||||
{
|
||||
get { return _deviceType; }
|
||||
set { _deviceType = value; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int RefreshFrequency
|
||||
{
|
||||
get { return _refreshFrequency; }
|
||||
set { _refreshFrequency = value; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public Dictionary<WeatherValueType, Value> Values
|
||||
{
|
||||
get { return _valueList; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public List<WeatherValueType> SupportedValues
|
||||
{
|
||||
get { return _valueList.Keys.ToList(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public methods
|
||||
|
||||
public Value GetValue(WeatherValueType valueType)
|
||||
{
|
||||
return _valueList[valueType];
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
72
Devices/HumidityDevice.cs
Normal file
72
Devices/HumidityDevice.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.Runtime.Serialization;
|
||||
using OneWireAPI;
|
||||
using WeatherService.Values;
|
||||
|
||||
namespace WeatherService.Devices
|
||||
{
|
||||
[DataContract]
|
||||
public class HumidityDevice : DeviceBase
|
||||
{
|
||||
#region Member variables
|
||||
|
||||
private readonly Value _temperatureValue;
|
||||
private readonly Value _humidityValue;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public HumidityDevice(Session session, owDevice device) : base(session, device, DeviceType.Humidity)
|
||||
{
|
||||
_temperatureValue = new Value(WeatherValueType.Temperature, this);
|
||||
_humidityValue = new Value(WeatherValueType.Humidity, this);
|
||||
|
||||
_valueList.Add(WeatherValueType.Temperature, _temperatureValue);
|
||||
_valueList.Add(WeatherValueType.Humidity, _humidityValue);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal methods
|
||||
|
||||
internal override void RefreshCache()
|
||||
{
|
||||
_temperatureValue.SetValue(ReadTemperature());
|
||||
_humidityValue.SetValue(ReadHumidity());
|
||||
|
||||
base.RefreshCache();
|
||||
}
|
||||
|
||||
internal double ReadTemperature()
|
||||
{
|
||||
// Cast the device to its specific type
|
||||
owDeviceFamily26 oDevice = (owDeviceFamily26) _device;
|
||||
|
||||
// Return the temperature from the device
|
||||
return oDevice.GetTemperature();
|
||||
}
|
||||
|
||||
internal double ReadHumidity()
|
||||
{
|
||||
// Cast the device to its specific type
|
||||
owDeviceFamily26 oDevice = (owDeviceFamily26) _device;
|
||||
|
||||
// Get the supply voltage
|
||||
double dSupplyVoltage = oDevice.GetSupplyVoltage();
|
||||
|
||||
// Get the output voltage
|
||||
double dOutputVoltage = oDevice.GetOutputVoltage();
|
||||
|
||||
// Get the temperature
|
||||
double dTemperature = oDevice.GetTemperature();
|
||||
|
||||
// Calculate the humidity
|
||||
double dHumidity = (((dOutputVoltage / dSupplyVoltage) - 0.16F) / 0.0062F) / (1.0546F - 0.00216F * dTemperature);
|
||||
|
||||
// Return the result
|
||||
return dHumidity;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
510
Devices/PressureDevice.cs
Normal file
510
Devices/PressureDevice.cs
Normal file
@@ -0,0 +1,510 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using OneWireAPI;
|
||||
using WeatherService.Values;
|
||||
|
||||
namespace WeatherService.Devices
|
||||
{
|
||||
[DataContract]
|
||||
public class PressureDevice : DeviceBase
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private readonly byte[] _resetSequence = new byte[] { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 }; // Binary sequence to reset the device
|
||||
private readonly byte[] _readWord1Sequence = new byte[] { 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0 }; // Binary sequence to read word 1
|
||||
private readonly byte[] _readWord2Sequence = new byte[] { 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0 }; // Binary sequence to read word 2
|
||||
private readonly byte[] _readWord3Sequence = new byte[] { 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0 }; // Binary sequence to read word 3
|
||||
private readonly byte[] _readWord4Sequence = new byte[] { 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0 }; // Binary sequence to read word 4
|
||||
private readonly byte[] _readPressureSequence = new byte[] { 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0 }; // Binary sequence to read pressure
|
||||
private readonly byte[] _readTemperatureSequence = new byte[] { 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0 }; // Binary sequence to read temperature
|
||||
|
||||
private const byte ChannelAccessCommand = 0xF5;
|
||||
private const byte ConfigRead = 0xEC;
|
||||
private const byte ConfigWrite = 0x8C;
|
||||
private const byte ConfigPulseRead = 0xC8;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Member variables
|
||||
|
||||
private readonly owDeviceFamily12 _writeDevice; // Device for writing to the pressure sensor
|
||||
private readonly owDeviceFamily12 _readDevice; // Device for reading from the pressure sensor
|
||||
private readonly Value _temperatureValue; // Last temperature (degrees C)
|
||||
private readonly Value _pressureValue; // Last pressure (mbar)
|
||||
|
||||
private bool _readCalibration; // Have we read the calibration constants?
|
||||
|
||||
private int _calibration1; // Calibration constant
|
||||
private int _calibration2; // Calibration constant
|
||||
private int _calibration3; // Calibration constant
|
||||
private int _calibration4; // Calibration constant
|
||||
private int _calibration5; // Calibration constant
|
||||
private int _calibration6; // Calibration constant
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public PressureDevice(Session session, owDevice firstDevice, owDevice secondDevice) : base(session, firstDevice, DeviceType.Pressure)
|
||||
{
|
||||
// Get both devices
|
||||
owDeviceFamily12 oDevice1 = (owDeviceFamily12) firstDevice;
|
||||
owDeviceFamily12 oDevice2 = (owDeviceFamily12) secondDevice;
|
||||
|
||||
// Get the state of both devices
|
||||
byte[] baState1 = oDevice1.ReadDevice();
|
||||
byte[] baState2 = oDevice2.ReadDevice();
|
||||
|
||||
// If both devices have the same power state then this isn't a proper pressure device
|
||||
if (oDevice1.IsPowered(baState1) == oDevice2.IsPowered(baState2))
|
||||
{
|
||||
// Throw an exception
|
||||
throw new Exception("Invalid TAI8570");
|
||||
}
|
||||
|
||||
// The powered device is the write device - sort this out and remember which is which
|
||||
if (oDevice1.IsPowered(baState1))
|
||||
{
|
||||
_writeDevice = oDevice1;
|
||||
_readDevice = oDevice2;
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeDevice = oDevice2;
|
||||
_readDevice = oDevice1;
|
||||
}
|
||||
|
||||
_temperatureValue = new Value(WeatherValueType.Temperature, this);
|
||||
_pressureValue = new Value(WeatherValueType.Pressure, this);
|
||||
|
||||
_valueList.Add(WeatherValueType.Temperature, _temperatureValue);
|
||||
_valueList.Add(WeatherValueType.Pressure, _pressureValue);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PIO methods
|
||||
|
||||
private void PrepPioForWrite()
|
||||
{
|
||||
byte[] baState = _writeDevice.ReadDevice();
|
||||
_writeDevice.SetLatchState(0, true, baState);
|
||||
_writeDevice.SetLatchState(1, false, baState);
|
||||
_writeDevice.WriteDevice(baState);
|
||||
|
||||
baState = _readDevice.ReadDevice();
|
||||
_readDevice.SetLatchState(0, false, baState);
|
||||
_readDevice.SetLatchState(1, false, baState);
|
||||
_readDevice.WriteDevice(baState);
|
||||
}
|
||||
|
||||
private void PrepPioForRead()
|
||||
{
|
||||
byte[] baState = _readDevice.ReadDevice();
|
||||
_readDevice.SetLatchState(0, false, baState);
|
||||
_readDevice.SetLatchState(1, false, baState);
|
||||
_readDevice.WriteDevice(baState);
|
||||
|
||||
baState = _writeDevice.ReadDevice();
|
||||
_writeDevice.SetLatchState(0, false, baState);
|
||||
_writeDevice.SetLatchState(1, false, baState);
|
||||
_writeDevice.WriteDevice(baState);
|
||||
}
|
||||
|
||||
private bool OpenPio(int pio)
|
||||
{
|
||||
byte[] baWriteState = _writeDevice.ReadDevice();
|
||||
byte[] baReadState = _readDevice.ReadDevice();
|
||||
|
||||
_writeDevice.SetLatchState(pio, false, baWriteState);
|
||||
_readDevice.SetLatchState(pio, false, baReadState);
|
||||
|
||||
_writeDevice.WriteDevice(baWriteState);
|
||||
_writeDevice.WriteDevice(baReadState);
|
||||
|
||||
baWriteState = _writeDevice.ReadDevice();
|
||||
baReadState = _readDevice.ReadDevice();
|
||||
|
||||
bool bResult = (_writeDevice.GetLevel(pio, baWriteState) && _readDevice.GetLevel(pio, baReadState));
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
private bool OpenPioA()
|
||||
{
|
||||
return OpenPio(0);
|
||||
}
|
||||
|
||||
private bool OpenPioB()
|
||||
{
|
||||
return OpenPio(1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
private bool SetupForWrite()
|
||||
{
|
||||
byte[] data = new byte[3]; // Data buffer to send over the network
|
||||
short dataCount = 0; // How many bytes of data to send
|
||||
|
||||
PrepPioForWrite();
|
||||
|
||||
owAdapter.Select(_writeDevice.ID);
|
||||
|
||||
data[dataCount++] = ChannelAccessCommand;
|
||||
data[dataCount++] = ConfigWrite;
|
||||
data[dataCount++] = 0xFF;
|
||||
|
||||
owAdapter.SendBlock(data, dataCount);
|
||||
|
||||
owAdapter.ReadByte();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SetupForRead()
|
||||
{
|
||||
byte[] data = new byte[3]; // Data buffer to send over the network
|
||||
short dataCount = 0; // How many bytes of data to send
|
||||
|
||||
PrepPioForRead();
|
||||
|
||||
owAdapter.Select(_readDevice.ID);
|
||||
|
||||
data[dataCount++] = ChannelAccessCommand;
|
||||
data[dataCount++] = ConfigRead;
|
||||
data[dataCount++] = 0xFF;
|
||||
|
||||
owAdapter.SendBlock(data, dataCount);
|
||||
|
||||
owAdapter.ReadByte();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SetupForPulseRead()
|
||||
{
|
||||
byte[] data = new byte[3]; // Data buffer to send over the network
|
||||
short dataCount = 0; // How many bytes of data to send
|
||||
|
||||
PrepPioForWrite();
|
||||
|
||||
owAdapter.Select(_readDevice.ID);
|
||||
|
||||
data[dataCount++] = ChannelAccessCommand;
|
||||
data[dataCount++] = ConfigPulseRead;
|
||||
data[dataCount++] = 0xFF;
|
||||
|
||||
owAdapter.SendBlock(data, dataCount);
|
||||
|
||||
owAdapter.ReadByte();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool WriteBitSequence(IEnumerable<byte> sequence)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (SetupForWrite())
|
||||
{
|
||||
foreach (byte t in sequence)
|
||||
{
|
||||
SendBit(t != 0);
|
||||
}
|
||||
|
||||
SendBit(false);
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte[] ReadBitSequence(IEnumerable<byte> sequence)
|
||||
{
|
||||
byte[] result = new byte[16];
|
||||
|
||||
if (WriteBitSequence(sequence))
|
||||
{
|
||||
result = GetBits(16);
|
||||
OpenPioB();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void SendBit(bool value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
owAdapter.SendBit(0);
|
||||
owAdapter.SendBit(1);
|
||||
owAdapter.SendBit(1);
|
||||
owAdapter.SendBit(1);
|
||||
owAdapter.SendBit(0);
|
||||
owAdapter.SendBit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
owAdapter.SendBit(0);
|
||||
owAdapter.SendBit(0);
|
||||
owAdapter.SendBit(1);
|
||||
owAdapter.SendBit(0);
|
||||
owAdapter.SendBit(0);
|
||||
owAdapter.SendBit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ReadBit()
|
||||
{
|
||||
owAdapter.ReadBit(); // Read PIO A #1
|
||||
owAdapter.ReadBit(); // Read PIO B #1
|
||||
owAdapter.ReadBit(); // Read PIO A #2
|
||||
owAdapter.ReadBit(); // Read PIO B #2
|
||||
owAdapter.ReadBit(); // Read PIO A #3
|
||||
owAdapter.ReadBit(); // Read PIO B #3
|
||||
owAdapter.ReadBit(); // Read PIO A #4
|
||||
short data = owAdapter.ReadBit();
|
||||
|
||||
bool result = (data == 1);
|
||||
|
||||
owAdapter.SendBit(0); // Write PIO A #1
|
||||
owAdapter.SendBit(1); // Write PIO B #1
|
||||
owAdapter.SendBit(0); // Write PIO A #2
|
||||
owAdapter.SendBit(1); // Write PIO B #2
|
||||
owAdapter.SendBit(1); // Write PIO A #3
|
||||
owAdapter.SendBit(1); // Write PIO B #3
|
||||
owAdapter.SendBit(1); // Write PIO A #4
|
||||
owAdapter.SendBit(1); // Write PIO B #4
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool Reset()
|
||||
{
|
||||
return WriteBitSequence(_resetSequence);
|
||||
}
|
||||
|
||||
private bool CheckConversionStatus()
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!SetupForPulseRead())
|
||||
return false;
|
||||
|
||||
for (i = 0; i < 100; i++)
|
||||
if (owAdapter.SendBit(0) == 0)
|
||||
break;
|
||||
|
||||
return (i < 100);
|
||||
}
|
||||
|
||||
private bool ReadCalibrationConstants()
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!Reset()) return false;
|
||||
|
||||
byte[] word1 = ReadBitSequence(_readWord1Sequence);
|
||||
|
||||
byte[] word2 = ReadBitSequence(_readWord2Sequence);
|
||||
|
||||
byte[] word3 = ReadBitSequence(_readWord3Sequence);
|
||||
|
||||
byte[] word4 = ReadBitSequence(_readWord4Sequence);
|
||||
|
||||
_calibration1 = _calibration2 = _calibration3 = _calibration4 = _calibration5 = _calibration6 = 0;
|
||||
|
||||
for (i = 0; i < 15; i++)
|
||||
{
|
||||
_calibration1 = (_calibration1 << 1);
|
||||
|
||||
if (word1[i] == 1)
|
||||
_calibration1 = _calibration1 + 1;
|
||||
}
|
||||
|
||||
if (word1[15] == 1)
|
||||
_calibration5 = 1;
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
_calibration5 = (_calibration5 << 1);
|
||||
|
||||
if (word2[i] == 1)
|
||||
_calibration5 = _calibration5 + 1;
|
||||
}
|
||||
|
||||
for (i = 10; i < 16; i++)
|
||||
{
|
||||
_calibration6 = (_calibration6 << 1);
|
||||
|
||||
if (word2[i] == 1)
|
||||
_calibration6 = _calibration6 + 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
_calibration4 = (_calibration4 << 1);
|
||||
|
||||
if (word3[i] == 1)
|
||||
_calibration4 = _calibration4 + 1;
|
||||
}
|
||||
|
||||
for (i = 10; i < 16; i++)
|
||||
{
|
||||
_calibration2 = (_calibration2 << 1);
|
||||
|
||||
if (word3[i] == 1)
|
||||
_calibration2 = _calibration2 + 1;
|
||||
}
|
||||
|
||||
for (i = 10; i < 16; i++)
|
||||
{
|
||||
_calibration2 = (_calibration2 << 1);
|
||||
|
||||
if (word4[i] == 1)
|
||||
_calibration2 = _calibration2 + 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
_calibration3 = (_calibration3 << 1);
|
||||
|
||||
if (word4[i] == 1)
|
||||
_calibration3 = _calibration3 + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private byte[] GetBits(byte bitCount)
|
||||
{
|
||||
byte[] result = new byte[bitCount];
|
||||
|
||||
if (SetupForRead())
|
||||
{
|
||||
for (int i = 0; i < bitCount; i++)
|
||||
{
|
||||
if (ReadBit())
|
||||
result[i] = 1;
|
||||
else
|
||||
result[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ReadValue(IEnumerable<byte> sequence)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (!Reset())
|
||||
return 0;
|
||||
|
||||
if (!WriteBitSequence(sequence))
|
||||
return 0;
|
||||
|
||||
if (!CheckConversionStatus())
|
||||
return 0;
|
||||
|
||||
if (!OpenPioA())
|
||||
return 0;
|
||||
|
||||
byte[] data = GetBits(16);
|
||||
|
||||
if (!OpenPioB())
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
result = (result << 1);
|
||||
|
||||
if (data[i] == 1)
|
||||
result = result + 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool ReadSensorData()
|
||||
{
|
||||
int pressure = ReadValue(_readPressureSequence);
|
||||
int temperature = ReadValue(_readTemperatureSequence);
|
||||
|
||||
double calibrationTemperature = (8 * _calibration5) + 20224;
|
||||
double temperatureDifference = temperature - calibrationTemperature;
|
||||
_temperatureValue.SetValue(20 + ((temperatureDifference * (_calibration6 + 50)) / 10240));
|
||||
|
||||
double offset = _calibration2 * 4 + (((_calibration4 - 512) * temperatureDifference) / 4096);
|
||||
double sensitivity = _calibration1 + ((_calibration3 * temperatureDifference) / 1024) + 24576;
|
||||
double actualPressure = ((sensitivity * (pressure - 7168)) / 16384) - offset;
|
||||
|
||||
_pressureValue.SetValue((actualPressure / 32) + 250);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ReadDevice()
|
||||
{
|
||||
if (!_readCalibration)
|
||||
{
|
||||
if (!ReadCalibrationConstants())
|
||||
throw new Exception("Error reading calibration constants");
|
||||
|
||||
_readCalibration = true;
|
||||
}
|
||||
|
||||
if (!ReadSensorData())
|
||||
throw new Exception("Error reading Pressure and Temperature values");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal methods
|
||||
|
||||
internal override void RefreshCache()
|
||||
{
|
||||
ReadDevice();
|
||||
|
||||
base.RefreshCache();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Elevation code (not used yet)
|
||||
|
||||
//private double m_dElevation = 0.0; // Height above sea level (meters)
|
||||
|
||||
//public void set_height_over_sea_level_meter(double height)
|
||||
//{
|
||||
// m_dElevation = height;
|
||||
//}
|
||||
|
||||
//public void set_height_over_sea_level_feet(double height)
|
||||
//{
|
||||
// m_dElevation = height * 0.3048;
|
||||
//}
|
||||
|
||||
//public double get_height_over_sea_level_meter()
|
||||
//{
|
||||
// return m_dElevation;
|
||||
//}
|
||||
|
||||
//public double get_height_over_sea_level_feet()
|
||||
//{
|
||||
// return (3.281 * m_dElevation);
|
||||
//}
|
||||
|
||||
//public double get_calc_height_over_sea_level_meter()
|
||||
//{
|
||||
// return (288.15 / 0.0065) * (1 - Math.Pow((double) (getPressure_Pa() / 101325), (double) (0.0065 * (287.052 / 9.81))));
|
||||
//}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
111
Devices/RainDevice.cs
Normal file
111
Devices/RainDevice.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using System.Runtime.Serialization;
|
||||
using OneWireAPI;
|
||||
using WeatherService.Values;
|
||||
|
||||
namespace WeatherService.Devices
|
||||
{
|
||||
[DataContract]
|
||||
public class RainDevice : DeviceBase
|
||||
{
|
||||
#region Member variables
|
||||
|
||||
private readonly Value _recentValue;
|
||||
|
||||
private readonly uint _clearedCount; // Counter at least clear
|
||||
|
||||
private uint _lastCount; // Counter from last check
|
||||
private uint _startupCount; // Counter at startup
|
||||
private bool _initialized;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public RainDevice(Session session, owDevice device)
|
||||
: base(session, device, DeviceType.Rain)
|
||||
{
|
||||
// TODO - Read the count as of the last counter clearing
|
||||
_clearedCount = 150;
|
||||
|
||||
// Get a reference to the device
|
||||
owDeviceFamily1D counter = (owDeviceFamily1D) _device;
|
||||
|
||||
// Get the current counter
|
||||
_lastCount = counter.GetCounter(15);
|
||||
|
||||
// Setup the rain value
|
||||
_recentValue = new Value(WeatherValueType.Rain, this);
|
||||
_valueList.Add(WeatherValueType.Rain, _recentValue);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal methods
|
||||
|
||||
internal override void RefreshCache()
|
||||
{
|
||||
double recentRain = ReadRecentRainfall();
|
||||
|
||||
_recentValue.SetValue(recentRain);
|
||||
|
||||
base.RefreshCache();
|
||||
}
|
||||
|
||||
internal double ReadSessionRainfall()
|
||||
{
|
||||
// Get a reference to the device
|
||||
owDeviceFamily1D counter = (owDeviceFamily1D) _device;
|
||||
|
||||
// If we haven't initialized then do it now
|
||||
if (!_initialized)
|
||||
{
|
||||
// Get the current counter
|
||||
_startupCount = counter.GetCounter(15);
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
// Get the current counter
|
||||
uint currentCount = counter.GetCounter(15);
|
||||
|
||||
// Get the amount of rain since the last check
|
||||
return (currentCount - _startupCount) * 0.2;
|
||||
}
|
||||
|
||||
internal double ReadRecentRainfall()
|
||||
{
|
||||
// Get a reference to the device
|
||||
owDeviceFamily1D counter = (owDeviceFamily1D) _device;
|
||||
|
||||
// Get the current counter
|
||||
uint currentCount = counter.GetCounter(15);
|
||||
|
||||
// Get the amount of rain since the last check
|
||||
double rainValue = (currentCount - _lastCount) * 0.2;
|
||||
|
||||
// Store the last counter
|
||||
_lastCount = currentCount;
|
||||
|
||||
return rainValue;
|
||||
}
|
||||
|
||||
internal double ReadTotalRainfall()
|
||||
{
|
||||
// Get a reference to the device
|
||||
owDeviceFamily1D counter = (owDeviceFamily1D) _device;
|
||||
|
||||
// Get the current counter
|
||||
uint currentCount = counter.GetCounter(15);
|
||||
|
||||
// Get the amount of rain since the last check
|
||||
double rainValue = (currentCount - _clearedCount) * 0.2F;
|
||||
|
||||
// Store the last counter
|
||||
_lastCount = currentCount;
|
||||
|
||||
return rainValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
49
Devices/TemperatureDevice.cs
Normal file
49
Devices/TemperatureDevice.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Runtime.Serialization;
|
||||
using OneWireAPI;
|
||||
using WeatherService.Values;
|
||||
|
||||
namespace WeatherService.Devices
|
||||
{
|
||||
[DataContract]
|
||||
public class TemperatureDevice : DeviceBase
|
||||
{
|
||||
#region Member variables
|
||||
|
||||
private readonly Value _temperatureValue; // Cached temperature
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public TemperatureDevice(Session session, owDevice device) : base(session, device, DeviceType.Temperature)
|
||||
{
|
||||
// Create the new value object
|
||||
_temperatureValue = new Value(WeatherValueType.Temperature, this);
|
||||
|
||||
_valueList.Add(WeatherValueType.Temperature, _temperatureValue);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal methods
|
||||
|
||||
internal override void RefreshCache()
|
||||
{
|
||||
// Read the current temperature
|
||||
_temperatureValue.SetValue(ReadTemperature());
|
||||
|
||||
base.RefreshCache();
|
||||
}
|
||||
|
||||
internal double ReadTemperature()
|
||||
{
|
||||
// Cast the device to its specific type
|
||||
owDeviceFamily10 temperatureDevice = (owDeviceFamily10) _device;
|
||||
|
||||
// Return the temperature from the device
|
||||
return temperatureDevice.GetTemperature();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
161
Devices/WindDirectionDevice.cs
Normal file
161
Devices/WindDirectionDevice.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
using System.Runtime.Serialization;
|
||||
using OneWireAPI;
|
||||
using WeatherService.Values;
|
||||
|
||||
namespace WeatherService.Devices
|
||||
{
|
||||
#region Enumerations
|
||||
|
||||
[DataContract]
|
||||
public enum WindDirection
|
||||
{
|
||||
[EnumMember]
|
||||
North,
|
||||
|
||||
[EnumMember]
|
||||
NorthNorthEast,
|
||||
|
||||
[EnumMember]
|
||||
NorthEast,
|
||||
|
||||
[EnumMember]
|
||||
EastNorthEast,
|
||||
|
||||
[EnumMember]
|
||||
East,
|
||||
|
||||
[EnumMember]
|
||||
EastSouthEast,
|
||||
|
||||
[EnumMember]
|
||||
SouthEast,
|
||||
|
||||
[EnumMember]
|
||||
SouthSouthEast,
|
||||
|
||||
[EnumMember]
|
||||
South,
|
||||
|
||||
[EnumMember]
|
||||
SouthSouthWest,
|
||||
|
||||
[EnumMember]
|
||||
SouthWest,
|
||||
|
||||
[EnumMember]
|
||||
WestSouthWest,
|
||||
|
||||
[EnumMember]
|
||||
West,
|
||||
|
||||
[EnumMember]
|
||||
WestNorthWest,
|
||||
|
||||
[EnumMember]
|
||||
NorthWest,
|
||||
|
||||
[EnumMember]
|
||||
NorthNorthWest,
|
||||
|
||||
[EnumMember]
|
||||
Unknown = -1
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[DataContract]
|
||||
public class WindDirectionDevice : DeviceBase
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const double WindowOffset = 0.7;
|
||||
|
||||
private readonly double[,] _lookupTable = { {4.66, 4.66, 2.38, 4.66}, // 0
|
||||
{4.66, 3.18, 3.20, 4.64}, // 1
|
||||
{4.66, 2.38, 4.66, 4.66}, // 2
|
||||
{3.20, 3.20, 4.66, 4.64}, // 3
|
||||
{2.38, 4.66, 4.66, 4.66}, // 4
|
||||
{2.36, 4.62, 4.60, 0.06}, // 5
|
||||
{4.64, 4.64, 4.64, 0.06}, // 6
|
||||
{4.60, 4.60, 0.06, 0.06}, // 7
|
||||
{4.64, 4.64, 0.06, 4.64}, // 8
|
||||
{4.62, 0.06, 0.06, 4.60}, // 9
|
||||
{4.64, 0.06, 4.64, 4.64}, // 10
|
||||
{0.06, 0.06, 4.60, 4.60}, // 11
|
||||
{0.06, 4.64, 4.64, 4.64}, // 12
|
||||
{0.06, 4.62, 4.62, 2.34}, // 13
|
||||
{4.66, 4.66, 4.66, 2.38}, // 14
|
||||
{4.66, 4.66, 3.18, 3.18} }; // 15
|
||||
|
||||
#endregion
|
||||
|
||||
#region Member variables
|
||||
|
||||
private readonly Value _directionValue; // Cached direction value
|
||||
|
||||
private bool _initialized; // Has the device been initialized
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public WindDirectionDevice(Session session, owDevice device)
|
||||
: base(session, device, DeviceType.WindDirection)
|
||||
{
|
||||
// Create the value
|
||||
_directionValue = new Value(WeatherValueType.WindDirection, this);
|
||||
|
||||
_valueList.Add(WeatherValueType.WindDirection, _directionValue);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal methods
|
||||
|
||||
internal override void RefreshCache()
|
||||
{
|
||||
_directionValue.SetValue((double)ReadDirection());
|
||||
|
||||
base.RefreshCache();
|
||||
}
|
||||
|
||||
internal WindDirection ReadDirection()
|
||||
{
|
||||
int direction = -1; // Decoded direction
|
||||
|
||||
// Cast the device as the specific device
|
||||
owDeviceFamily20 voltage = (owDeviceFamily20)_device;
|
||||
|
||||
// If we haven't initialized the device we need to do it now
|
||||
if (!_initialized)
|
||||
{
|
||||
// Initialize the device
|
||||
voltage.Initialize();
|
||||
|
||||
// Remember that we've done this
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
// Get the array of voltages from the device
|
||||
double[] voltages = voltage.GetVoltages();
|
||||
|
||||
// Loop over the lookup table to find the direction that maps to the voltages
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (((voltages[0] <= _lookupTable[i, 0] + WindowOffset) && (voltages[0] >= _lookupTable[i, 0] - WindowOffset)) &&
|
||||
((voltages[1] <= _lookupTable[i, 1] + WindowOffset) && (voltages[1] >= _lookupTable[i, 1] - WindowOffset)) &&
|
||||
((voltages[2] <= _lookupTable[i, 2] + WindowOffset) && (voltages[2] >= _lookupTable[i, 2] - WindowOffset)) &&
|
||||
((voltages[3] <= _lookupTable[i, 3] + WindowOffset) && (voltages[3] >= _lookupTable[i, 3] - WindowOffset)))
|
||||
{
|
||||
direction = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the direction
|
||||
return (WindDirection)direction;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
76
Devices/WindSpeedDevice.cs
Normal file
76
Devices/WindSpeedDevice.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Serialization;
|
||||
using OneWireAPI;
|
||||
using WeatherService.Values;
|
||||
|
||||
namespace WeatherService.Devices
|
||||
{
|
||||
[DataContract]
|
||||
public class WindSpeedDevice : DeviceBase
|
||||
{
|
||||
#region Member variables
|
||||
|
||||
private readonly Value _speedValue; // Cached speed value
|
||||
|
||||
private long _lastTicks; // Last time we checked the counter
|
||||
private uint _lastCount; // The count at the last check
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public WindSpeedDevice(Session session, owDevice device) : base(session, device, DeviceType.WindSpeed)
|
||||
{
|
||||
_speedValue = new Value(WeatherValueType.WindSpeed, this);
|
||||
|
||||
_valueList.Add(WeatherValueType.WindSpeed, _speedValue);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal methods
|
||||
|
||||
internal override void RefreshCache()
|
||||
{
|
||||
_speedValue.SetValue(ReadSpeed());
|
||||
|
||||
base.RefreshCache();
|
||||
}
|
||||
|
||||
internal double ReadSpeed()
|
||||
{
|
||||
// Get a reference to the device
|
||||
owDeviceFamily1D counterDevice = (owDeviceFamily1D) _device;
|
||||
|
||||
// Special case if we have never read before
|
||||
if (_lastTicks == 0)
|
||||
{
|
||||
// Initialize the last data to the data now
|
||||
_lastTicks = Stopwatch.GetTimestamp();
|
||||
_lastCount = counterDevice.GetCounter(15);
|
||||
|
||||
// Wait for a second
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
// Get the current counter and time
|
||||
uint currentCount = counterDevice.GetCounter(15);
|
||||
long currentTicks = Stopwatch.GetTimestamp();
|
||||
|
||||
// Get the time difference in seconds
|
||||
double timeDifference = (double) (currentTicks - _lastTicks) / Stopwatch.Frequency;
|
||||
|
||||
// Figure out how many revolutions per second in the last interval
|
||||
double revolutionsPerSecond = ((currentCount - _lastCount) / timeDifference) / 2D;
|
||||
|
||||
// Store the current time and counter
|
||||
_lastTicks = currentTicks;
|
||||
_lastCount = currentCount;
|
||||
|
||||
// Convert the revolutions per second to wind speed
|
||||
return (revolutionsPerSecond * 2.453F);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user