Add desired property Config.SetPointTemp and Config.TelemetryInterval

Expected behavior when desired.Config.SetPointTemp updated:
1. The mid-point (or average value) of temperature was updated
2. The reported property sharing the same name was update

Expected behavior when desired.Config.TelemetryInterval updated:
1. The telemetry interval (a.k.a. report interval) was updated (unit: seconds)
2. The reported property sharing the same name was update

Both the two desired properties will be persisted on the IoT Hub. So the effect will always be there, no matter the simulator was reboot or not, except the property was removed manually. Then it will use the default value:
SetPointTemp: 34.5
TelemetryInterval: 5 second
This commit is contained in:
Xiangzhi Sheng 2017-01-11 12:02:04 +08:00
Родитель 918396ffb8
Коммит 799c1210e4
8 изменённых файлов: 143 добавлений и 35 удалений

Просмотреть файл

@ -26,9 +26,9 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Common.SampleDat
private long _tickCounter;
object sync = new Object();
public SampleDataGenerator(double minValueToGenerate,
double maxNonPeakValueToGenerate, double minPeakValueToGenerate,
int peakInterval, IRandomGenerator randomGenerator)
public SampleDataGenerator(double minValueToGenerate,
double maxNonPeakValueToGenerate, double minPeakValueToGenerate,
int peakInterval, IRandomGenerator randomGenerator)
{
if (minValueToGenerate >= maxNonPeakValueToGenerate)
{
@ -50,7 +50,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Common.SampleDat
// minPeakValueToGenerate is zero when peaks are not generated
_generatePeaks = minPeakValueToGenerate != 0 ? true : false;
if (_generatePeaks && peakInterval == 0)
{
throw new ArgumentOutOfRangeException("peakInterval", "peakInterval cannot be 0.");
@ -82,21 +82,21 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Common.SampleDat
}
public SampleDataGenerator(double minValueToGenerate, double maxNonPeakValueToGenerate,
public SampleDataGenerator(double minValueToGenerate, double maxNonPeakValueToGenerate,
double minPeakValueToGenerate, int peakInterval)
: this(minValueToGenerate, maxNonPeakValueToGenerate, minPeakValueToGenerate,
: this(minValueToGenerate, maxNonPeakValueToGenerate, minPeakValueToGenerate,
peakInterval, new RandomGenerator())
{
}
public SampleDataGenerator(double minValueToGenerate, double maxNonPeakValueToGenerate,
public SampleDataGenerator(double minValueToGenerate, double maxNonPeakValueToGenerate,
IRandomGenerator randomGenerator)
: this(minValueToGenerate, maxNonPeakValueToGenerate, 0, 0, randomGenerator)
{
}
public SampleDataGenerator(double minValueToGenerate, double maxNonPeakValueToGenerate)
: this (minValueToGenerate, maxNonPeakValueToGenerate, 0, 0, new RandomGenerator())
public SampleDataGenerator(double minValueToGenerate, double maxNonPeakValueToGenerate)
: this(minValueToGenerate, maxNonPeakValueToGenerate, 0, 0, new RandomGenerator())
{
}
@ -132,6 +132,11 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Common.SampleDat
}
}
public double GetMidPointOfRange()
{
return (_minValueToGenerate + _maxNonPeakValueToGenerate) / 2;
}
private void GetNextRawValue()
{
double adjustment = ((2.0 * _deltaValue) * _randomGenerator.GetRandomDouble()) - _deltaValue;

Просмотреть файл

@ -10,6 +10,7 @@ using Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob.Sim
using Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob.SimulatorCore.Devices;
using Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob.SimulatorCore.Devices.DMTasks;
using Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob.SimulatorCore.Logging;
using Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob.SimulatorCore.Telemetry;
using Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob.SimulatorCore.Telemetry.Factory;
using Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob.SimulatorCore.Transport.Factory;
using Microsoft.Azure.Devices.Client;
@ -29,6 +30,8 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
ITelemetryFactory telemetryFactory, IConfigurationProvider configurationProvider)
: base(logger, transportFactory, telemetryFactory, configurationProvider)
{
_desiredPropertyUdateHandlers.Add(SetPointTempPropertyName, OnSetPointTempUpdate);
_desiredPropertyUdateHandlers.Add(TelemetryIntervalPropertyName, OnTelemetryIntervalUpdate);
}
/// <summary>
@ -75,7 +78,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
public void ChangeSetPointTemp(double setPointTemp)
{
var remoteMonitorTelemetry = (RemoteMonitorTelemetry)_telemetryController;
remoteMonitorTelemetry.ChangeSetPointTemperature(setPointTemp);
remoteMonitorTelemetry.SetPointTemperature = setPointTemp;
Logger.LogInfo("Device {0} temperature changed to {1}", DeviceID, setPointTemp);
}
@ -272,5 +275,21 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
}
await Transport.UpdateReportedPropertiesAsync(collection);
}
protected async Task OnSetPointTempUpdate(object value)
{
var telemetry = _telemetryController as ITelemetryWithSetPointTemperature;
telemetry.SetPointTemperature = Convert.ToDouble(value);
await SetReportedPropertyAsync(SetPointTempPropertyName, telemetry.SetPointTemperature);
}
protected async Task OnTelemetryIntervalUpdate(object value)
{
var telemetry = _telemetryController as ITelemetryWithInterval;
telemetry.TelemetryIntervalInSeconds = Convert.ToInt32(value);
await SetReportedPropertyAsync(TelemetryIntervalPropertyName, telemetry.TelemetryIntervalInSeconds);
}
}
}

Просмотреть файл

@ -8,7 +8,7 @@ using Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob.Sim
namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob.Cooler.Telemetry
{
public class RemoteMonitorTelemetry : ITelemetry
public class RemoteMonitorTelemetry : ITelemetry, ITelemetryWithInterval, ITelemetryWithSetPointTemperature
{
private readonly ILogger _logger;
private readonly string _deviceId;
@ -32,11 +32,13 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
ActivateExternalTemperature = false;
TelemetryActive = true;
int peakFrequencyInTicks = Convert.ToInt32(Math.Ceiling((double)PEAK_FREQUENCY_IN_SECONDS / REPORT_FREQUENCY_IN_SECONDS));
int peakFrequencyInTicks = Convert.ToInt32(Math.Ceiling((double)PEAK_FREQUENCY_IN_SECONDS / REPORT_FREQUENCY_IN_SECONDS));
_temperatureGenerator = new SampleDataGenerator(33, 36, 42, peakFrequencyInTicks);
_humidityGenerator = new SampleDataGenerator(20, 50);
_externalTemperatureGenerator = new SampleDataGenerator(-20, 120);
TelemetryIntervalInSeconds = REPORT_FREQUENCY_IN_SECONDS;
}
public async Task SendEventsAsync(CancellationToken token, Func<object, Task> sendMessageAsync)
@ -67,13 +69,23 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
await sendMessageAsync(monitorData);
}
await Task.Delay(TimeSpan.FromSeconds(REPORT_FREQUENCY_IN_SECONDS), token);
await Task.Delay(TimeSpan.FromSeconds(TelemetryIntervalInSeconds), token);
}
}
public void ChangeSetPointTemperature(double newSetPointTemperature)
public int TelemetryIntervalInSeconds { get; set; }
public double SetPointTemperature
{
_temperatureGenerator.ShiftSubsequentData(newSetPointTemperature);
get
{
return _temperatureGenerator.GetMidPointOfRange();
}
set
{
_temperatureGenerator.ShiftSubsequentData(value);
}
}
}
}

Просмотреть файл

@ -29,6 +29,8 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
public const string StartupTimePropertyName = "StartupTime";
public const string FirmwareVersionPropertyName = "FirmwareVersion";
public const string ConfigurationVersionPropertyName = "ConfigurationVersion";
public const string SetPointTempPropertyName = "Config.SetPointTemp";
public const string TelemetryIntervalPropertyName = "Config.TelemetryInterval";
// pointer to the currently executing event group
private int _currentEventGroup = 0;
@ -168,10 +170,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
{
try
{
await Transport.OpenAsync();
await UpdateReportedPropertiesAsync();
SetMethodHandlers();
await InitializeAsync();
var loopTasks = new List<Task>
{
@ -191,6 +190,16 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
}
}
private async Task InitializeAsync()
{
await Transport.OpenAsync();
SetupCallbacks();
var twin = await Transport.GetTwinAsync();
await UpdateReportedPropertiesAsync(twin.Properties.Reported);
await OnDesiredPropertyUpdate(twin.Properties.Desired, null);
}
/// <summary>
/// Iterates through the list of IEventGroups and fires off the events in a given event group before moving to the next.
/// If RepeatEventListForever is true the device will continue to loop through each event group, if false
@ -351,14 +360,12 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
Logger.LogInfo("********** Processing Device {0} has been cancelled - StartReceiveLoopAsync Ending. **********", DeviceID);
}
protected async Task UpdateReportedPropertiesAsync(bool regenerate = false)
protected async Task UpdateReportedPropertiesAsync(TwinCollection reported, bool regenerate = false)
{
var reported = await Transport.GetReportedPropertiesAsync();
var patch = new TwinCollection();
CrossSyncProperties(patch, reported, regenerate);
AddSupportedMethods(patch, reported);
patch.Set(StartupTimePropertyName, DateTime.UtcNow.ToString());
AddConfigs(patch);
// Update ReportedProperties to IoT Hub
await Transport.UpdateReportedPropertiesAsync(patch);
@ -454,13 +461,58 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
patch["SupportedMethods"] = supportedMethods;
}
private void SetMethodHandlers()
protected void AddConfigs(TwinCollection patch)
{
var telemetryWithInterval = _telemetryController as ITelemetryWithInterval;
if (telemetryWithInterval != null)
{
patch.Set(TelemetryIntervalPropertyName, telemetryWithInterval.TelemetryIntervalInSeconds);
}
var telemetryWithSetPointTemp = _telemetryController as ITelemetryWithSetPointTemperature;
if (telemetryWithSetPointTemp != null)
{
patch.Set(SetPointTempPropertyName, telemetryWithSetPointTemp.SetPointTemperature);
}
patch.Set(StartupTimePropertyName, DateTime.UtcNow.ToString());
}
private void SetupCallbacks()
{
foreach (var method in Commands.Where(c => c.DeliveryType == DeliveryType.Method))
{
var callback = GetType().GetMethod($"On{method.Name}").CreateDelegate(typeof(MethodCallback), this) as MethodCallback;
try
{
var handler = GetType().GetMethod($"On{method.Name}").CreateDelegate(typeof(MethodCallback), this) as MethodCallback;
Transport.SetMethodHandler(method.Name, callback);
Transport.SetMethodHandler(method.Name, handler);
}
catch (Exception ex)
{
Logger.LogError($"Exception raised while adding callback for method {method.Name}: {ex}");
}
}
Transport.SetDesiredPropertyUpdateCallback(OnDesiredPropertyUpdate);
}
public async Task OnDesiredPropertyUpdate(TwinCollection desiredProperties, object userContext)
{
foreach (var pair in desiredProperties.AsEnumerableFlatten())
{
Func<object, Task> handler;
if (_desiredPropertyUdateHandlers.TryGetValue(pair.Key, out handler))
{
try
{
await handler(pair.Value.Value.Value);
}
catch (Exception ex)
{
Logger.LogError($"Exception raised while processing desired property {pair.Key} change: {ex}");
}
}
}
}
}

Просмотреть файл

@ -22,4 +22,14 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
/// <returns>Task that completes when all tasks are sent</returns>
Task SendEventsAsync(CancellationToken token, Func<object, Task> sendMessageAsync);
}
public interface ITelemetryWithInterval
{
int TelemetryIntervalInSeconds { get; set; }
}
public interface ITelemetryWithSetPointTemperature
{
double SetPointTemperature { get; set; }
}
}

Просмотреть файл

@ -94,17 +94,21 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
await Task.FromResult(0);
}
public async Task<TwinCollection> GetReportedPropertiesAsync()
public async Task<Twin> GetTwinAsync()
{
_logger.LogInfo("GetReportedPropertiesAsync called");
_logger.LogInfo("GetTwinAsync called");
return await Task.FromResult(new TwinCollection());
return await Task.FromResult(new Twin());
}
public void SetMethodHandler(string methodName, MethodCallback callback)
{
_logger.LogInfo("SetMethodHandler called:");
_logger.LogInfo($"SetMethodHandler: methodName: {methodName}");
_logger.LogInfo($"SetMethodHandler called: {methodName} -> {callback.Method.Name}");
}
public void SetDesiredPropertyUpdateCallback(DesiredPropertyUpdateCallback callback)
{
_logger.LogInfo($"SetDesiredPropertyUpdateCallback called, callback = {callback.Method.Name}");
}
}
}

Просмотреть файл

@ -31,8 +31,10 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
Task UpdateReportedPropertiesAsync(TwinCollection reportedProperties);
Task<TwinCollection> GetReportedPropertiesAsync();
Task<Twin> GetTwinAsync();
void SetMethodHandler(string methodName, MethodCallback callback);
void SetDesiredPropertyUpdateCallback(DesiredPropertyUpdateCallback callback);
}
}

Просмотреть файл

@ -285,10 +285,9 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
await _deviceClient.UpdateReportedPropertiesAsync(reportedProperties);
}
public async Task<TwinCollection> GetReportedPropertiesAsync()
public async Task<Twin> GetTwinAsync()
{
var twin = await _deviceClient.GetTwinAsync();
return twin.Properties.Reported;
return await _deviceClient.GetTwinAsync();
}
public void SetMethodHandler(string methodName, MethodCallback callback)
@ -296,6 +295,11 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.Simulator.WebJob
_deviceClient.SetMethodHandler(methodName, callback, null);
}
public void SetDesiredPropertyUpdateCallback(DesiredPropertyUpdateCallback callback)
{
_deviceClient.SetDesiredPropertyUpdateCallback(callback, null);
}
/// <summary>
/// Implement the IDisposable interface in order to close the device manager
/// </summary>