This commit is contained in:
Spyros Garyfallos 2018-06-17 13:59:06 -07:00
Родитель cf8d0191b9
Коммит 40f0571b17
89 изменённых файлов: 938 добавлений и 414 удалений

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

@ -0,0 +1,30 @@

using Microsoft.Azure.IoT.TypeEdge.Modules;
using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using ThermostatApplication.Messages;
using ThermostatApplication.Modules;
namespace Modules
{
public class AnomalyDetection : EdgeModule, IAnomalyDetection
{
public Input<Temperature> Temperature { get; set; }
public Input<Reference<Sample>> Samples { get; set; }
public Output<Anomaly> Anomaly { get; set; }
public AnomalyDetection(IPreprocessor preprocessor, IDataSampling trainer)
{
Temperature.Subscribe(preprocessor.Detection, async signal =>
{
return MessageResult.Ok;
});
Samples.Subscribe(trainer.Samples, async (sampleReference) =>
{
System.Console.WriteLine("New Sample");
System.Console.WriteLine($"Length = {sampleReference.Message.Data.Length}");
return MessageResult.Ok;
});
}
}
}

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

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<ApplicationIcon />
<LangVersion>latest</LangVersion>
<OutputType>Exe</OutputType>
<Configurations>Debug;Release;TemplateDevelopment</Configurations>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" Condition="'$(Configuration)|$(Platform)'!='TemplateDevelopment|AnyCPU'" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Microsoft.Azure.IoT.TypeEdge\Microsoft.Azure.IoT.TypeEdge.csproj" Condition="'$(Configuration)|$(Platform)'=='TemplateDevelopment|AnyCPU'" />
<ProjectReference Include="..\..\Thermostat.Shared\Thermostat.Shared.csproj" />
</ItemGroup>
</Project>

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

@ -0,0 +1,22 @@
ARG base_tag=2.1.0-runtime-bionic
FROM microsoft/dotnet:${base_tag} AS base
WORKDIR /app
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY Modules/AnomalyDetection/AnomalyDetection.csproj Modules/AnomalyDetection/
COPY Thermostat.Shared/Thermostat.Shared.csproj Thermostat.Shared/
COPY NuGet.Config ./
RUN dotnet restore Modules/AnomalyDetection/AnomalyDetection.csproj
COPY . .
WORKDIR /src/Modules/AnomalyDetection
RUN dotnet build AnomalyDetection.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish AnomalyDetection.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "AnomalyDetection.dll"]

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

@ -0,0 +1,37 @@

using Microsoft.Azure.IoT.TypeEdge.Modules;
using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using System.Collections.Generic;
using ThermostatApplication.Messages;
using ThermostatApplication.Modules;
namespace Modules
{
public class DataSampling : EdgeModule, IDataSampling
{
List<Temperature> _sample;
public Input<Temperature> Temperature { get; set; }
public Output<Reference<Sample>> Samples { get; set; }
public DataSampling(IPreprocessor proxy)
{
_sample = new List<Temperature>();
Temperature.Subscribe(proxy.Training, async signal =>
{
_sample.Add(signal);
if (_sample.Count > 999)
{
await Samples.PublishAsync(new Reference<Sample>()
{
Message = new Sample() { Data = _sample.ToArray() }
});
_sample.Clear();
}
return MessageResult.Ok;
});
}
}
}

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

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<ApplicationIcon />
<LangVersion>latest</LangVersion>
<OutputType>Exe</OutputType>
<Configurations>Debug;Release;TemplateDevelopment</Configurations>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" Condition="'$(Configuration)|$(Platform)'!='TemplateDevelopment|AnyCPU'" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Microsoft.Azure.IoT.TypeEdge\Microsoft.Azure.IoT.TypeEdge.csproj" Condition="'$(Configuration)|$(Platform)'=='TemplateDevelopment|AnyCPU'" />
<ProjectReference Include="..\..\Thermostat.Shared\Thermostat.Shared.csproj" />
</ItemGroup>
</Project>

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

@ -0,0 +1,22 @@
ARG base_tag=2.1.0-runtime-bionic
FROM microsoft/dotnet:${base_tag} AS base
WORKDIR /app
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY Modules/DataSampling/DataSampling.csproj Modules/DataSampling/
COPY Thermostat.Shared/Thermostat.Shared.csproj Thermostat.Shared/
COPY NuGet.Config ./
RUN dotnet restore Modules/DataSampling/DataSampling.csproj
COPY . .
WORKDIR /src/Modules/DataSampling
RUN dotnet build DataSampling.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish DataSampling.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "DataSampling.dll"]

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

@ -1,21 +0,0 @@
FROM microsoft/dotnet:2.1-runtime AS base
WORKDIR /app
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY Modules/NormalizeTemperatureModule/NormalizeTemperatureModule.csproj Modules/NormalizeTemperatureModule/
COPY Thermostat.Shared/Thermostat.Shared.csproj Thermostat.Shared/
COPY NuGet.Config ./
RUN dotnet restore Modules/NormalizeTemperatureModule/NormalizeTemperatureModule.csproj
COPY . .
WORKDIR /src/Modules/NormalizeTemperatureModule
RUN dotnet build NormalizeTemperatureModule.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish NormalizeTemperatureModule.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "NormalizeTemperatureModule.dll"]

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

@ -1,55 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.IoT.TypeEdge.Enums;
using Microsoft.Azure.IoT.TypeEdge.Modules;
using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Modules.Enums;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using Microsoft.Azure.IoT.TypeEdge.Twins;
using ThermostatApplication;
using ThermostatApplication.Messages;
using ThermostatApplication.Modules;
using ThermostatApplication.Twins;
namespace Modules
{
public class NormalizeTemperatureModule : EdgeModule, INormalizeTemperatureModule
{
//memory state
private TemperatureScale _scale;
public NormalizeTemperatureModule(ITemperatureModule proxy)
{
Temperature.Subscribe(proxy.Temperature, async temp =>
{
Console.WriteLine("New Message in NormalizeTemperatureModule.");
if (temp.Scale != _scale)
if (_scale == TemperatureScale.Celsius)
temp.Temperature = temp.Temperature * 9 / 5 + 32;
await NormalizedTemperature.PublishAsync(temp);
return MessageResult.Ok;
});
Twin.Subscribe(async twin =>
{
_scale = twin.Scale;
await Twin.ReportAsync(twin);
return TwinResult.Ok;
});
}
public Input<TemperatureModuleOutput> Temperature { get; set; }
public Output<TemperatureModuleOutput> NormalizedTemperature { get; set; }
public ModuleTwin<NormalizerTwin> Twin { get; set; }
public override async Task<ExecutionResult> RunAsync()
{
var twin = await Twin.GetAsync();
_scale = twin.Scale;
return ExecutionResult.Ok;
}
}
}

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

@ -0,0 +1,22 @@
ARG base_tag=2.1.0-runtime-bionic
FROM microsoft/dotnet:${base_tag} AS base
WORKDIR /app
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY Modules/Preprocessor/Preprocessor.csproj Modules/Preprocessor/
COPY Thermostat.Shared/Thermostat.Shared.csproj Thermostat.Shared/
COPY NuGet.Config ./
RUN dotnet restore Modules/Preprocessor/Preprocessor.csproj
COPY . .
WORKDIR /src/Modules/Preprocessor
RUN dotnet build Preprocessor.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish Preprocessor.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Preprocessor.dll"]

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

@ -0,0 +1,76 @@
using System.Threading.Tasks;
using Microsoft.Azure.IoT.TypeEdge.Enums;
using Microsoft.Azure.IoT.TypeEdge.Modules;
using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Modules.Enums;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using Microsoft.Azure.IoT.TypeEdge.Twins;
using ThermostatApplication;
using ThermostatApplication.Messages;
using ThermostatApplication.Modules;
using ThermostatApplication.Twins;
namespace Modules
{
public class Preprocessor : EdgeModule, IPreprocessor
{
public Input<Temperature> Temperature { get; set; }
public Output<Temperature> Training { get; set; }
public Output<Temperature> Detection { get; set; }
public ModuleTwin<PreprocessorTwin> Twin { get; set; }
public Preprocessor(ITemperatureSensor proxy)
{
Temperature.Subscribe(proxy.Temperature, async signal =>
{
var twin = Twin.LastKnownTwin;
if (twin != null)
{
if (signal.Scale != twin.Scale)
if (twin.Scale == TemperatureScale.Celsius)
signal.Value = signal.Value * 9 / 5 + 32;
await RouteMessageAsync(signal, twin.RoutingMode);
}
return MessageResult.Ok;
});
Twin.Subscribe(async twin =>
{
System.Console.WriteLine($"Preprocessor: new routing : { twin.RoutingMode.ToString()}");
await Twin.ReportAsync(twin);
return TwinResult.Ok;
});
}
private async Task RouteMessageAsync(Temperature signal, Routing mode)
{
switch (mode)
{
case Routing.None:
break;
case Routing.Train:
await Training.PublishAsync(signal);
break;
case Routing.Detect:
await Detection.PublishAsync(signal);
break;
case Routing.Both:
var results = new Task<PublishResult>[] {
Training.PublishAsync(signal),
Detection.PublishAsync(signal)
};
await Task.WhenAll(results);
break;
default:
break;
}
}
public override async Task<ExecutionResult> RunAsync()
{
await Twin.GetAsync();
return ExecutionResult.Ok;
}
}
}

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

@ -13,7 +13,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" Condition="'$(Configuration)|$(Platform)'!='TemplateDevelopment|AnyCPU'"/>
</ItemGroup>
<ItemGroup>

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

@ -0,0 +1,13 @@
using System.Threading.Tasks;
using Microsoft.Azure.IoT.TypeEdge;
namespace Modules
{
internal class Program
{
public static async Task Main(string[] args)
{
await Startup.DockerEntryPoint(args);
}
}
}

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

@ -1,20 +0,0 @@
FROM microsoft/dotnet:2.1-runtime AS base
WORKDIR /app
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY Modules/TemperatureModule/TemperatureModule.csproj Modules/TemperatureModule/
COPY Thermostat.Shared/Thermostat.Shared.csproj Thermostat.Shared/
COPY NuGet.Config ./
RUN dotnet restore Modules/TemperatureModule/TemperatureModule.csproj
COPY . .
WORKDIR /src/Modules/TemperatureModule
RUN dotnet build TemperatureModule.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish TemperatureModule.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "TemperatureModule.dll"]

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

@ -0,0 +1,21 @@
ARG base_tag=2.1.0-runtime-bionic
FROM microsoft/dotnet:${base_tag} AS base
WORKDIR /app
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY Modules/TemperatureSensor/TemperatureSensor.csproj Modules/TemperatureSensor/
COPY Thermostat.Shared/Thermostat.Shared.csproj Thermostat.Shared/
COPY NuGet.Config ./
RUN dotnet restore Modules/TemperatureSensor/TemperatureSensor.csproj
COPY . .
WORKDIR /src/Modules/TemperatureSensor
RUN dotnet build TemperatureSensor.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish TemperatureSensor.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "TemperatureSensor.dll"]

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

@ -0,0 +1,13 @@
using System.Threading.Tasks;
using Microsoft.Azure.IoT.TypeEdge;
namespace Modules
{
internal class Program
{
public static async Task Main(string[] args)
{
await Startup.DockerEntryPoint(args);
}
}
}

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

@ -12,9 +12,9 @@ using ThermostatApplication.Twins;
namespace Modules
{
public class TemperatureModule : EdgeModule, ITemperatureModule
public class TemperatureSensor : EdgeModule, ITemperatureSensor
{
public Output<TemperatureModuleOutput> Temperature { get; set; }
public Output<Temperature> Temperature { get; set; }
public ModuleTwin<TemperatureTwin> Twin { get; set; }
public bool ResetSensor(int sensitivity)
@ -25,16 +25,32 @@ namespace Modules
public override async Task<ExecutionResult> RunAsync()
{
double frequency = 0.5;
int offset = 70;
int amplitute = 10;
int samplingRate = 25;
while (true)
{
await Temperature.PublishAsync(new TemperatureModuleOutput
var sin = Math.Sin(2 * Math.PI * frequency * DateTime.Now.TimeOfDay.TotalSeconds);
var value = amplitute
* sin
+ offset;
await Temperature.PublishAsync(new Temperature
{
Scale = TemperatureScale.Celsius,
Temperature = new Random().NextDouble() * 100
Value = value
});
Thread.Sleep(10);
}
int left = 40;
left = (int)(sin * left) + left;
var text = new string('-', left);
Console.WriteLine($"{value.ToString("F2")} {text}");
Thread.Sleep(1000 / samplingRate);
}
return await base.RunAsync();
}
}

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

@ -13,7 +13,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" Condition="'$(Configuration)|$(Platform)'!='TemplateDevelopment|AnyCPU'"/>
</ItemGroup>
<ItemGroup>

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

@ -1,4 +1,5 @@
FROM microsoft/dotnet:2.1-runtime AS base
ARG base_tag=2.1.0-runtime-bionic
FROM microsoft/dotnet:${base_tag} AS base
# Add an unprivileged user account for running Edge Hub
RUN useradd -ms /bin/bash edgehubuser
@ -35,8 +36,10 @@ FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY Thermostat.Emulator/Thermostat.Emulator.csproj Thermostat.Emulator/
COPY Thermostat.Shared/Thermostat.Shared.csproj Thermostat.Shared/
COPY Modules/NormalizeTemperatureModule/NormalizeTemperatureModule.csproj Modules/NormalizeTemperatureModule/
COPY Modules/TemperatureModule/TemperatureModule.csproj Modules/TemperatureModule/
COPY Modules/Preprocessor/Preprocessor.csproj Modules/Preprocessor/
COPY Modules/TemperatureSensor/TemperatureSensor.csproj Modules/TemperatureSensor/
COPY Modules/DataSampling/DataSampling.csproj Modules/DataSampling/
COPY Modules/AnomalyDetection/AnomalyDetection.csproj Modules/AnomalyDetection/
COPY ./.env Thermostat.Emulator/
COPY NuGet.Config ./
RUN dotnet restore Thermostat.Emulator/Thermostat.Emulator.csproj

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

@ -21,10 +21,12 @@ namespace ThermostatApplication
var host = new TypeEdgeHost(configuration);
host.RegisterModule<ITemperatureModule, TemperatureModule>();
host.RegisterModule<INormalizeTemperatureModule, NormalizeTemperatureModule>();
host.RegisterModule<ITemperatureSensor, TemperatureSensor>();
host.RegisterModule<IPreprocessor, Preprocessor>();
host.RegisterModule<IDataSampling, DataSampling>();
host.RegisterModule<IAnomalyDetection, AnomalyDetection>();
host.Upstream.Subscribe(host.GetProxy<INormalizeTemperatureModule>().NormalizedTemperature);
host.Upstream.Subscribe(host.GetProxy<IPreprocessor>().Detection);
host.Build();

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

@ -18,15 +18,17 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.68" Condition="'$(Configuration)|$(Platform)'!='TemplateDevelopment|AnyCPU'" />
<PackageReference Include="rocksdb-native-arm" Version="5.4.6" />
<PackageReference Include="RocksDbNative" Version="5.4.6.10" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Microsoft.Azure.IoT.TypeEdge.Host\Microsoft.Azure.IoT.TypeEdge.Host.csproj" Condition="'$(Configuration)|$(Platform)'=='TemplateDevelopment|AnyCPU'" />
<ProjectReference Include="..\Modules\NormalizeTemperatureModule\NormalizeTemperatureModule.csproj" />
<ProjectReference Include="..\Modules\TemperatureModule\TemperatureModule.csproj" />
<ProjectReference Include="..\Modules\AnomalyDetection\AnomalyDetection.csproj" />
<ProjectReference Include="..\Modules\DataSampling\DataSampling.csproj" />
<ProjectReference Include="..\Modules\Preprocessor\Preprocessor.csproj" />
<ProjectReference Include="..\Modules\TemperatureSensor\TemperatureSensor.csproj" />
<ProjectReference Include="..\Thermostat.Shared\Thermostat.Shared.csproj" />
</ItemGroup>

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

@ -1,7 +1,7 @@
{
"TypeEdgeHost": {
"IotHubConnectionString": "",
"DeviceId": "type-edge-dev8",
"IotHubConnectionString": "HostName=bugbashtypeedge.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=Ce7B3aoIyPwqdus+yTXQCkMmcqIfRE02ddRWLG5Zs7M=",
"DeviceId": "type-edge-dev",
"PrintDeploymentJson": "true"
}
}

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

@ -11,9 +11,29 @@ namespace Thermostat.ServiceApp
{
private static async Task Main(string[] args)
{
Console.WriteLine("Press <ENTER> to start..");
Console.ReadLine();
ThermostatApplication.Twins.Routing routing = ThermostatApplication.Twins.Routing.None;
while (true)
{
Console.WriteLine("Select Processor routing mode : (N)one, (T)rain, (D)etect, (B)oth");
var res = Console.ReadLine();
switch (res.ToUpper())
{
case "T":
routing = ThermostatApplication.Twins.Routing.Train;
break;
case "N":
break;
case "D":
routing = ThermostatApplication.Twins.Routing.Detect;
break;
case "B":
routing = ThermostatApplication.Twins.Routing.Both;
break;
default:
continue;
}
break;
}
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings_thermostat.json")
.AddEnvironmentVariables()
@ -22,13 +42,14 @@ namespace Thermostat.ServiceApp
ProxyFactory.Configure(configuration["IotHubConnectionString"],
configuration["DeviceId"]);
var normalizer = ProxyFactory.GetModuleProxy<INormalizeTemperatureModule>();
var normalizer = ProxyFactory.GetModuleProxy<IPreprocessor>();
var twin = await normalizer.Twin.GetAsync();
twin.Scale = TemperatureScale.Celsius;
twin.RoutingMode = routing;
await normalizer.Twin.PublishAsync(twin);
var result = ProxyFactory.GetModuleProxy<ITemperatureModule>().ResetSensor(10);
//var result = ProxyFactory.GetModuleProxy<ITemperatureSensor>().ResetSensor(10);
Console.WriteLine("Press <ENTER> to exit..");
Console.ReadLine();

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

@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.68" Condition="'$(Configuration)|$(Platform)'!='TemplateDevelopment|AnyCPU'"/>
</ItemGroup>

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

@ -1,5 +1,4 @@
{
"DeviceId": "type-edge-dev",
"IotHubConnectionString":
"HostName=iotedgedev-iothub-7389d7.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=68K3zvI8CKbN7NM5s46N9rlP+zvPHPJKg7shy1rwMRU="
"IotHubConnectionString": "HostName=bugbashtypeedge.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=Ce7B3aoIyPwqdus+yTXQCkMmcqIfRE02ddRWLG5Zs7M="
}

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

@ -0,0 +1,12 @@
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text;
namespace ThermostatApplication.Messages
{
public class Anomaly : EdgeMessage
{
public double Value { get; set; }
}
}

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

@ -0,0 +1,9 @@
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
namespace ThermostatApplication.Messages
{
public class Sample : EdgeMessage
{
public Temperature[] Data { get; set; }
}
}

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

@ -0,0 +1,14 @@

using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text;
namespace ThermostatApplication.Messages
{
public class Temperature : EdgeMessage
{
public TemperatureScale Scale { get; set; }
public double Value { get; set; }
}
}

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

@ -1,25 +0,0 @@
using System.Collections.Generic;
using System.Text;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using Newtonsoft.Json;
namespace ThermostatApplication.Messages
{
public class TemperatureModuleInput : IEdgeMessage
{
public int MyData { get; set; }
public IDictionary<string, string> Properties { get; set; }
public byte[] GetBytes()
{
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this));
}
public void SetBytes(byte[] bytes)
{
var obj = JsonConvert.DeserializeObject<TemperatureModuleInput>(Encoding.UTF8.GetString(bytes));
Properties = obj.Properties;
MyData = obj.MyData;
}
}
}

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

@ -1,27 +0,0 @@
using System.Collections.Generic;
using System.Text;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using Newtonsoft.Json;
namespace ThermostatApplication.Messages
{
public class TemperatureModuleOutput : IEdgeMessage
{
public TemperatureScale Scale { get; set; }
public double Temperature { get; set; }
public IDictionary<string, string> Properties { get; set; }
public byte[] GetBytes()
{
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this));
}
public void SetBytes(byte[] bytes)
{
var obj = JsonConvert.DeserializeObject<TemperatureModuleOutput>(Encoding.UTF8.GetString(bytes));
Properties = obj.Properties;
Scale = obj.Scale;
Temperature = obj.Temperature;
}
}
}

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

@ -0,0 +1,16 @@
using Microsoft.Azure.IoT.TypeEdge.Attributes;
using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using ThermostatApplication.Messages;
namespace ThermostatApplication.Modules
{
[TypeModule]
public interface IAnomalyDetection
{
Input<Temperature> Temperature { get; set; }
Input<Reference<Sample>> Samples { get; set; }
Output<Anomaly> Anomaly { get; set; }
}
}

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

@ -0,0 +1,14 @@
using Microsoft.Azure.IoT.TypeEdge.Attributes;
using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using ThermostatApplication.Messages;
namespace ThermostatApplication.Modules
{
[TypeModule]
public interface IDataSampling
{
Input<Temperature> Temperature { get; set; }
Output<Reference<Sample>> Samples { get; set; }
}
}

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

@ -7,10 +7,13 @@ using ThermostatApplication.Twins;
namespace ThermostatApplication.Modules
{
[TypeModule]
public interface INormalizeTemperatureModule
public interface IPreprocessor
{
Output<TemperatureModuleOutput> NormalizedTemperature { get; set; }
Input<Temperature> Temperature { get; set; }
ModuleTwin<NormalizerTwin> Twin { get; set; }
Output<Temperature> Training { get; set; }
Output<Temperature> Detection { get; set; }
ModuleTwin<PreprocessorTwin> Twin { get; set; }
}
}

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

@ -7,9 +7,9 @@ using ThermostatApplication.Twins;
namespace ThermostatApplication.Modules
{
[TypeModule]
public interface ITemperatureModule
public interface ITemperatureSensor
{
Output<TemperatureModuleOutput> Temperature { get; set; }
Output<Temperature> Temperature { get; set; }
ModuleTwin<TemperatureTwin> Twin { get; set; }
bool ResetSensor(int sensitivity);

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

@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" Condition="'$(Configuration)|$(Platform)'!='TemplateDevelopment|AnyCPU'" />
</ItemGroup>
<ItemGroup>

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

@ -1,9 +0,0 @@
using Microsoft.Azure.IoT.TypeEdge.Twins;
namespace ThermostatApplication.Twins
{
public class NormalizerTwin : TypeModuleTwin
{
public TemperatureScale Scale { get; set; }
}
}

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

@ -0,0 +1,17 @@
using Microsoft.Azure.IoT.TypeEdge.Twins;
namespace ThermostatApplication.Twins
{
public enum Routing {
None,
Train,
Detect,
Both
}
public class PreprocessorTwin : TypeModuleTwin
{
public TemperatureScale Scale { get; set; }
public Routing RoutingMode { get; set; }
}
}

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

@ -0,0 +1,10 @@
using Microsoft.Azure.IoT.TypeEdge.Volumes;
using ThermostatApplication.Messages;
namespace ThermostatApplication.Modules
{
public interface ISharedVolume
{
Volume<Sample> Samples { get; set; }
}
}

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

@ -7,9 +7,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{8D82
EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{1373DBDC-DC13-429E-8C17-2E4D85CF42BA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NormalizeTemperatureModule", "Modules\NormalizeTemperatureModule\NormalizeTemperatureModule.csproj", "{97D246B7-A79E-49A1-A9BA-2D1B8A6C26BF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preprocessor", "Modules\NormalizeTemperatureModule\Preprocessor.csproj", "{97D246B7-A79E-49A1-A9BA-2D1B8A6C26BF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemperatureModule", "Modules\TemperatureModule\TemperatureModule.csproj", "{73158509-5709-40DF-A5A9-89661B3000A7}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemperatureSensor", "Modules\TemperatureModule\TemperatureSensor.csproj", "{73158509-5709-40DF-A5A9-89661B3000A7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thermostat.Emulator", "Thermostat.Emulator\Thermostat.Emulator.csproj", "{1A622C23-B9BD-4903-A28D-28B446BB358E}"
EndProject
@ -17,6 +17,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thermostat.Shared", "Thermo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thermostat.ServiceApp", "Thermostat.ServiceApp\Thermostat.ServiceApp.csproj", "{258D1CCE-A112-46A2-88F1-D9BA50450C7B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModelTraining", "Modules\ModelTraining\ModelTraining.csproj", "{866235F5-B323-465F-A248-F7575F630E05}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnomalyDetection", "Modules\AnomalyDetection\AnomalyDetection.csproj", "{D29D8C1F-EEFD-42D7-A2AA-5F8DBBF44B06}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -60,6 +64,18 @@ Global
{258D1CCE-A112-46A2-88F1-D9BA50450C7B}.Release|Any CPU.Build.0 = Release|Any CPU
{258D1CCE-A112-46A2-88F1-D9BA50450C7B}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{258D1CCE-A112-46A2-88F1-D9BA50450C7B}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{866235F5-B323-465F-A248-F7575F630E05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{866235F5-B323-465F-A248-F7575F630E05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{866235F5-B323-465F-A248-F7575F630E05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{866235F5-B323-465F-A248-F7575F630E05}.Release|Any CPU.Build.0 = Release|Any CPU
{866235F5-B323-465F-A248-F7575F630E05}.TemplateDevelopment|Any CPU.ActiveCfg = Debug|Any CPU
{866235F5-B323-465F-A248-F7575F630E05}.TemplateDevelopment|Any CPU.Build.0 = Debug|Any CPU
{D29D8C1F-EEFD-42D7-A2AA-5F8DBBF44B06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D29D8C1F-EEFD-42D7-A2AA-5F8DBBF44B06}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D29D8C1F-EEFD-42D7-A2AA-5F8DBBF44B06}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D29D8C1F-EEFD-42D7-A2AA-5F8DBBF44B06}.Release|Any CPU.Build.0 = Release|Any CPU
{D29D8C1F-EEFD-42D7-A2AA-5F8DBBF44B06}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{D29D8C1F-EEFD-42D7-A2AA-5F8DBBF44B06}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -67,6 +83,8 @@ Global
GlobalSection(NestedProjects) = preSolution
{97D246B7-A79E-49A1-A9BA-2D1B8A6C26BF} = {8D822B22-E5A9-4165-B27B-458A70D2B44F}
{73158509-5709-40DF-A5A9-89661B3000A7} = {8D822B22-E5A9-4165-B27B-458A70D2B44F}
{866235F5-B323-465F-A248-F7575F630E05} = {8D822B22-E5A9-4165-B27B-458A70D2B44F}
{D29D8C1F-EEFD-42D7-A2AA-5F8DBBF44B06} = {8D822B22-E5A9-4165-B27B-458A70D2B44F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E7BE10A1-BBA6-43BB-BC65-A9D38A168E00}

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

@ -11,16 +11,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Example", "Example", "{C865
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{F2FF1756-9AAF-411B-8B54-3829EAC21515}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemperatureModule", "Example\Modules\TemperatureModule\TemperatureModule.csproj", "{48302C68-971D-414F-A29D-742F79415D74}"
ProjectSection(ProjectDependencies) = postProject
{54587D56-7C22-4084-9321-84D57C2F6ECB} = {54587D56-7C22-4084-9321-84D57C2F6ECB}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NormalizeTemperatureModule", "Example\Modules\NormalizeTemperatureModule\NormalizeTemperatureModule.csproj", "{30A335A6-47C9-435A-BA23-50988EAF2C33}"
ProjectSection(ProjectDependencies) = postProject
{54587D56-7C22-4084-9321-84D57C2F6ECB} = {54587D56-7C22-4084-9321-84D57C2F6ECB}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thermostat.Shared", "Example\Thermostat.Shared\Thermostat.Shared.csproj", "{45F97F43-7C75-49B8-8525-7F0E9C7B9FB7}"
ProjectSection(ProjectDependencies) = postProject
{54587D56-7C22-4084-9321-84D57C2F6ECB} = {54587D56-7C22-4084-9321-84D57C2F6ECB}
@ -40,6 +30,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thermostat.ServiceApp", "Ex
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.IoT.TypeEdge.Proxy", "Microsoft.Azure.IoT.TypeEdge.Proxy\Microsoft.Azure.IoT.TypeEdge.Proxy.csproj", "{E738845B-4D98-4CB9-BDA4-F83193FE81B5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnomalyDetection", "Example\Modules\AnomalyDetection\AnomalyDetection.csproj", "{5E31547C-97D8-4B42-A909-A9F7DA23E50D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataSampling", "Example\Modules\DataSampling\DataSampling.csproj", "{FAB78513-F407-4A4F-9908-00E0096C2979}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preprocessor", "Example\Modules\Preprocessor\Preprocessor.csproj", "{18137F45-9592-4E25-B718-630B21DF48DF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemperatureSensor", "Example\Modules\TemperatureSensor\TemperatureSensor.csproj", "{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CodeCoverage|Any CPU = CodeCoverage|Any CPU
@ -64,22 +62,6 @@ Global
{6F13F88C-B271-4DA6-9A35-5FD7FEADD3A3}.Release|Any CPU.Build.0 = Release|Any CPU
{6F13F88C-B271-4DA6-9A35-5FD7FEADD3A3}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{6F13F88C-B271-4DA6-9A35-5FD7FEADD3A3}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{48302C68-971D-414F-A29D-742F79415D74}.CodeCoverage|Any CPU.ActiveCfg = Debug|Any CPU
{48302C68-971D-414F-A29D-742F79415D74}.CodeCoverage|Any CPU.Build.0 = Debug|Any CPU
{48302C68-971D-414F-A29D-742F79415D74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48302C68-971D-414F-A29D-742F79415D74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48302C68-971D-414F-A29D-742F79415D74}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48302C68-971D-414F-A29D-742F79415D74}.Release|Any CPU.Build.0 = Release|Any CPU
{48302C68-971D-414F-A29D-742F79415D74}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{48302C68-971D-414F-A29D-742F79415D74}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{30A335A6-47C9-435A-BA23-50988EAF2C33}.CodeCoverage|Any CPU.ActiveCfg = Debug|Any CPU
{30A335A6-47C9-435A-BA23-50988EAF2C33}.CodeCoverage|Any CPU.Build.0 = Debug|Any CPU
{30A335A6-47C9-435A-BA23-50988EAF2C33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{30A335A6-47C9-435A-BA23-50988EAF2C33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30A335A6-47C9-435A-BA23-50988EAF2C33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30A335A6-47C9-435A-BA23-50988EAF2C33}.Release|Any CPU.Build.0 = Release|Any CPU
{30A335A6-47C9-435A-BA23-50988EAF2C33}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{30A335A6-47C9-435A-BA23-50988EAF2C33}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{45F97F43-7C75-49B8-8525-7F0E9C7B9FB7}.CodeCoverage|Any CPU.ActiveCfg = Debug|Any CPU
{45F97F43-7C75-49B8-8525-7F0E9C7B9FB7}.CodeCoverage|Any CPU.Build.0 = Debug|Any CPU
{45F97F43-7C75-49B8-8525-7F0E9C7B9FB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -112,17 +94,51 @@ Global
{E738845B-4D98-4CB9-BDA4-F83193FE81B5}.Release|Any CPU.Build.0 = Release|Any CPU
{E738845B-4D98-4CB9-BDA4-F83193FE81B5}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{E738845B-4D98-4CB9-BDA4-F83193FE81B5}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{5E31547C-97D8-4B42-A909-A9F7DA23E50D}.CodeCoverage|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{5E31547C-97D8-4B42-A909-A9F7DA23E50D}.CodeCoverage|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{5E31547C-97D8-4B42-A909-A9F7DA23E50D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5E31547C-97D8-4B42-A909-A9F7DA23E50D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E31547C-97D8-4B42-A909-A9F7DA23E50D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E31547C-97D8-4B42-A909-A9F7DA23E50D}.Release|Any CPU.Build.0 = Release|Any CPU
{5E31547C-97D8-4B42-A909-A9F7DA23E50D}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{5E31547C-97D8-4B42-A909-A9F7DA23E50D}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{FAB78513-F407-4A4F-9908-00E0096C2979}.CodeCoverage|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{FAB78513-F407-4A4F-9908-00E0096C2979}.CodeCoverage|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{FAB78513-F407-4A4F-9908-00E0096C2979}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAB78513-F407-4A4F-9908-00E0096C2979}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAB78513-F407-4A4F-9908-00E0096C2979}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAB78513-F407-4A4F-9908-00E0096C2979}.Release|Any CPU.Build.0 = Release|Any CPU
{FAB78513-F407-4A4F-9908-00E0096C2979}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{FAB78513-F407-4A4F-9908-00E0096C2979}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{18137F45-9592-4E25-B718-630B21DF48DF}.CodeCoverage|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{18137F45-9592-4E25-B718-630B21DF48DF}.CodeCoverage|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{18137F45-9592-4E25-B718-630B21DF48DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18137F45-9592-4E25-B718-630B21DF48DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18137F45-9592-4E25-B718-630B21DF48DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18137F45-9592-4E25-B718-630B21DF48DF}.Release|Any CPU.Build.0 = Release|Any CPU
{18137F45-9592-4E25-B718-630B21DF48DF}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{18137F45-9592-4E25-B718-630B21DF48DF}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5}.CodeCoverage|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5}.CodeCoverage|Any CPU.Build.0 = TemplateDevelopment|Any CPU
{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5}.Release|Any CPU.Build.0 = Release|Any CPU
{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5}.TemplateDevelopment|Any CPU.ActiveCfg = TemplateDevelopment|Any CPU
{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5}.TemplateDevelopment|Any CPU.Build.0 = TemplateDevelopment|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F2FF1756-9AAF-411B-8B54-3829EAC21515} = {C865B730-A5A7-4738-9F6E-CBC7AA306467}
{48302C68-971D-414F-A29D-742F79415D74} = {F2FF1756-9AAF-411B-8B54-3829EAC21515}
{30A335A6-47C9-435A-BA23-50988EAF2C33} = {F2FF1756-9AAF-411B-8B54-3829EAC21515}
{45F97F43-7C75-49B8-8525-7F0E9C7B9FB7} = {C865B730-A5A7-4738-9F6E-CBC7AA306467}
{2076DDEF-8EE3-4BC1-BF79-1C1F62A8719D} = {C865B730-A5A7-4738-9F6E-CBC7AA306467}
{286CDAA1-5410-4322-AC1C-F35A83CDA63D} = {C865B730-A5A7-4738-9F6E-CBC7AA306467}
{5E31547C-97D8-4B42-A909-A9F7DA23E50D} = {F2FF1756-9AAF-411B-8B54-3829EAC21515}
{FAB78513-F407-4A4F-9908-00E0096C2979} = {F2FF1756-9AAF-411B-8B54-3829EAC21515}
{18137F45-9592-4E25-B718-630B21DF48DF} = {F2FF1756-9AAF-411B-8B54-3829EAC21515}
{65C0C786-8C42-4B7D-A0B8-104FF9FA2CE5} = {F2FF1756-9AAF-411B-8B54-3829EAC21515}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {114E5850-267D-4B44-ACD5-91ACA382DDBC}

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

@ -2,14 +2,14 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Microsoft.Azure.IoT.TypeEdge.Host</id>
<version>0.1.55</version>
<version>0.1.68</version>
<authors>paloukari</authors>
<owners>paloukari</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Package Description</description>
<dependencies>
<group targetFramework=".NETCoreApp2.1">
<dependency id="Microsoft.Azure.IoT.TypeEdge" version="0.1.48" exclude="Build,Analyzers" />
<dependency id="Microsoft.Azure.IoT.TypeEdge" version="0.1.68" exclude="Build,Analyzers" />
<dependency id="Microsoft.Azure.Devices.Edge.Agent.Core" version="1.0.0" exclude="Build,Analyzers" />
<dependency id="Microsoft.Azure.Devices.Edge.Hub.Service" version="1.0.0" exclude="Build,Analyzers" />
</group>

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

@ -1,4 +1,4 @@
ARG base_tag=2.1-runtime-stretch-slim
ARG base_tag=2.1.0-runtime-bionic
FROM microsoft/dotnet:${base_tag}
# Add an unprivileged user account for running Edge Hub

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

@ -17,6 +17,7 @@ using Microsoft.Azure.IoT.TypeEdge.Modules;
using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using Microsoft.Azure.IoT.TypeEdge.Proxy;
using Microsoft.Azure.IoT.TypeEdge.Volumes;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
@ -159,12 +160,6 @@ namespace Microsoft.Azure.IoT.TypeEdge.Host
var csBuilder = IotHubConnectionStringBuilder.Create(_options.IotHubConnectionString);
//new ModuleConnectionString.ModuleConnectionStringBuilder(csBuilder.HostName, _options.DeviceId)
// .WithModuleId(Devices.Edge.Agent.Core.Constants.EdgeHubModuleName)
// .WithModuleId(Devices.Edge.Agent.Core.Constants.EdgeHubModuleIdentityName)
// .WithSharedAccessKey(deviceSasKey)
// .Build();
var edgeConnectionString =
new ModuleConnectionStringBuilder(csBuilder.HostName, _options.DeviceId)
.Create(Devices.Edge.Agent.Core.Constants.EdgeHubModuleIdentityName)
@ -241,6 +236,21 @@ namespace Microsoft.Azure.IoT.TypeEdge.Host
{
if (!(scope.Resolve(moduleType) is EdgeModule module))
continue;
//foreach (var item in module.GetType().GetProperties())
//{
// if (!item.PropertyType.IsGenericType)
// continue;
// var genericDef = item.PropertyType.GetGenericTypeDefinition();
// if (!genericDef.IsAssignableFrom(typeof(Volume<>)))
// continue;
// //the ctor of this prop registers the volume
// var instance = Activator.CreateInstance(
// genericDef.MakeGenericType(item.PropertyType.GenericTypeArguments),
// item.Name, module);
//}
modules.Add(module);
}
}
@ -282,6 +292,12 @@ namespace Microsoft.Azure.IoT.TypeEdge.Host
foreach (var module in _modules)
{
var volumes = "";
if (module.Volumes.Count > 0)
{
var v = String.Join(',', module.Volumes.Select(e => $"\"{$"/env/{e.Key.ToLower()}"}\": {{}}"));
volumes = $", \"Volumes\": {{ {v} }}";
}
modulesConfig?.Add(module.Name.ToLower(), JObject.FromObject(new
{
version = "1.0",
@ -292,7 +308,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Host
{
image = dockerRegistry + module.Name.ToLower(),
createOptions = "{\n \"Env\":[\n \"" + TypeEdge.Constants.ModuleNameConfigName + "=" +
module.Name.ToLower() + "\"\n ]\n}"
module.Name.ToLower() + $"\"\n ]\n {volumes} }}"
}
}));

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

@ -3,7 +3,7 @@
<PropertyGroup>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<PackageId>Microsoft.Azure.IoT.TypeEdge.Proxy</PackageId>
<Version>0.1.55</Version>
<Version>0.1.68</Version>
<Authors>paloukari</Authors>
<Company>Microsoft</Company>

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

@ -7,6 +7,7 @@ using Microsoft.Azure.IoT.TypeEdge.Attributes;
using Microsoft.Azure.IoT.TypeEdge.Modules;
using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Twins;
using Microsoft.Azure.IoT.TypeEdge.Volumes;
using Newtonsoft.Json;
namespace Microsoft.Azure.IoT.TypeEdge.Proxy
@ -47,7 +48,8 @@ namespace Microsoft.Azure.IoT.TypeEdge.Proxy
var genericDef = invocation.Method.ReturnType.GetGenericTypeDefinition();
if (genericDef.IsAssignableFrom(typeof(Input<>))
|| genericDef.IsAssignableFrom(typeof(Output<>))
|| genericDef.IsAssignableFrom(typeof(ModuleTwin<>)))
|| genericDef.IsAssignableFrom(typeof(ModuleTwin<>))
|| genericDef.IsAssignableFrom(typeof(Volume<>)))
{
var value = Activator.CreateInstance(
genericDef.MakeGenericType(invocation.Method.ReturnType.GenericTypeArguments),

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

@ -1,8 +0,0 @@
using System;
namespace Microsoft.Azure.IoT.TypeEdge.Attributes
{
internal class InputAttribute : Attribute
{
}
}

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

@ -1,8 +0,0 @@
using System;
namespace Microsoft.Azure.IoT.TypeEdge.Attributes
{
internal class OutputAttribute : Attribute
{
}
}

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

@ -73,7 +73,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.DovEnv
foreach (var basePath in basePaths)
{
var testPath = string.Join("/", new string[] { basePath, path });
Console.WriteLine($"DotEnv: checking for {testPath}");
//Console.WriteLine($"DotEnv: checking for {testPath}");
if (!File.Exists(testPath))
continue;
fileExists = true;

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

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Microsoft.Azure.IoT.TypeEdge
{
public static class Extensions
{
public static T1 CopyFrom<T1, T2>(this T1 obj, T2 otherObject)
where T1 : class
where T2 : class
{
PropertyInfo[] srcFields = otherObject.GetType().GetProperties(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);
PropertyInfo[] destFields = obj.GetType().GetProperties(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty);
foreach (var property in srcFields)
{
var dest = destFields.FirstOrDefault(x => x.Name == property.Name);
if (dest != null && dest.CanWrite)
dest.SetValue(obj, property.GetValue(otherObject, null), null);
}
return obj;
}
}
}

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

@ -3,7 +3,7 @@
<PropertyGroup>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<PackageId>Microsoft.Azure.IoT.TypeEdge</PackageId>
<Version>0.1.55</Version>
<Version>0.1.68</Version>
<Authors>paloukari</Authors>
<Company>Microsoft</Company>
<PackageOutputPath>../../TypeEdgeNuGets</PackageOutputPath>

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

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
@ -16,6 +15,7 @@ using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Modules.Enums;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using Microsoft.Azure.IoT.TypeEdge.Twins;
using Microsoft.Azure.IoT.TypeEdge.Volumes;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
@ -24,11 +24,10 @@ using Newtonsoft.Json;
namespace Microsoft.Azure.IoT.TypeEdge.Modules
{
public abstract class EdgeModule
public abstract class EdgeModule : IDisposable
{
private readonly Dictionary<string, MethodCallback> _methodSubscriptions;
private readonly Dictionary<string, SubscriptionCallback> _routeSubscriptions;
private readonly Dictionary<string, SubscriptionCallback> _twinSubscriptions;
private string _connectionString;
private ModuleClient _ioTHubModuleClient;
@ -39,6 +38,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
_routeSubscriptions = new Dictionary<string, SubscriptionCallback>();
_twinSubscriptions = new Dictionary<string, SubscriptionCallback>();
_methodSubscriptions = new Dictionary<string, MethodCallback>();
Volumes = new Dictionary<string, string>();
Routes = new List<string>();
@ -60,6 +60,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
internal List<string> Routes { get; set; }
public Dictionary<string, string> Volumes { get; }
internal virtual Task<T> PublishTwinAsync<T>(string name, T twin)
where T : IModuleTwin, new()
@ -95,7 +96,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
_ioTHubModuleClient = ModuleClient.CreateFromConnectionString(_connectionString, _transportSettings);
await _ioTHubModuleClient.OpenAsync();
Console.WriteLine($"{Name}:IoT Hub module client initialized.");
//Console.WriteLine($"{Name}:IoT Hub module client initialized.");
// Register callback to be called when a message is received by the module
foreach (var subscription in _routeSubscriptions)
@ -103,7 +104,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
await _ioTHubModuleClient.SetInputMessageHandlerAsync(subscription.Key, MessageHandler,
subscription.Value);
Console.WriteLine($"{Name}:MessageHandler set for {subscription.Key}");
//Console.WriteLine($"{Name}:MessageHandler set for {subscription.Key}");
}
// Register callback to be called when a twin update is received by the module
@ -112,16 +113,16 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
foreach (var subscription in _methodSubscriptions)
{
await _ioTHubModuleClient.SetMethodHandlerAsync(subscription.Key, MethodCallback, subscription.Value);
Console.WriteLine($"{Name}:MethodCallback set for{subscription.Key}");
//Console.WriteLine($"{Name}:MethodCallback set for{subscription.Key}");
}
Console.WriteLine($"{Name}:Running RunAsync..");
//Console.WriteLine($"{Name}:Running RunAsync..");
return await RunAsync();
}
private Task<MethodResponse> MethodCallback(MethodRequest methodRequest, object userContext)
{
Console.WriteLine($"{Name}:MethodCallback called");
//Console.WriteLine($"{Name}:MethodCallback called");
if (!(userContext is MethodCallback callback))
throw new InvalidOperationException($"{Name}:UserContext doesn't contain a valid SubscriptionCallback");
@ -140,6 +141,8 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
}
catch (Exception ex)
{
Console.WriteLine($"{Name}:ERROR:{ex}");
// Acknowlege the direct method call with a 400 error message
var result = "{\"result\":\"" + ex.Message + "\"}";
return Task.FromResult(new MethodResponse(Encoding.UTF8.GetBytes(result), 400));
@ -148,7 +151,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
internal CreationResult InternalConfigure(IConfigurationRoot configuration)
{
Console.WriteLine($"{Name}:InternalConfigure called");
//Console.WriteLine($"{Name}:InternalConfigure called");
_connectionString = configuration.GetValue<string>($"{Constants.EdgeHubConnectionStringKey}");
if (string.IsNullOrEmpty(_connectionString))
@ -171,9 +174,9 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
internal async Task<PublishResult> PublishMessageAsync<T>(string outputName, T message)
where T : IEdgeMessage
{
Console.WriteLine($"{Name}:PublishMessageAsync called");
//Console.WriteLine($"{Name}:PublishMessageAsync called");
var edgeMessage = new Message(message.GetBytes());
if (message.Properties != null)
foreach (var prop in edgeMessage.Properties)
@ -182,7 +185,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
await _ioTHubModuleClient.SendEventAsync(outputName, edgeMessage);
var messageString = Encoding.UTF8.GetString(message.GetBytes());
Console.WriteLine($">>>>>>{Name}: message: Body: [{messageString}]");
//Console.WriteLine($">>>>>>{Name}: message: Body: [{messageString}]");
return PublishResult.Ok;
}
@ -191,7 +194,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
Func<T, Task<MessageResult>> handler)
where T : IEdgeMessage
{
Console.WriteLine($"{Name}:SubscribeRoute called");
//Console.WriteLine($"{Name}:SubscribeRoute called");
if (outRoute != "$downstream")
Routes.Add($"FROM {outRoute} INTO {inRoute}");
@ -201,7 +204,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
internal void SubscribeRoute(string outName, string outRoute, string inName, string inRoute)
{
Console.WriteLine($"{Name}:SubscribeRoute called");
//Console.WriteLine($"{Name}:SubscribeRoute called");
if (outRoute != "$downstream")
Routes.Add($"FROM {outRoute} INTO {inRoute}");
@ -209,21 +212,21 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
internal void SubscribeTwin<T>(string name, Func<T, Task<TwinResult>> handler) where T : IModuleTwin
{
Console.WriteLine($"{Name}:SubscribeTwin called");
//Console.WriteLine($"{Name}:SubscribeTwin called");
_twinSubscriptions[name] = new SubscriptionCallback(name, handler, typeof(T));
}
private async Task<MessageResponse> MessageHandler(Message message, object userContext)
{
Console.WriteLine($"{Name}:MessageHandler called");
//Console.WriteLine($"{Name}:MessageHandler called");
if (!(userContext is SubscriptionCallback callback))
throw new InvalidOperationException("UserContext doesn't contain a valid SubscriptionCallback");
var messageBytes = message.GetBytes();
var messageString = Encoding.UTF8.GetString(messageBytes);
Console.WriteLine($"<<<<<<{Name}:message: Body: [{messageString}]");
//Console.WriteLine($"<<<<<<{Name}:message: Body: [{messageString}]");
if (!(Activator.CreateInstance(callback.Type) is IEdgeMessage input))
{
@ -241,13 +244,13 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
private async Task PropertyHandler(TwinCollection desiredProperties, object userContext)
{
Console.WriteLine($"{Name}:PropertyHandler called");
//Console.WriteLine($"{Name}:PropertyHandler called");
if (!(userContext is Dictionary<string, SubscriptionCallback> callbacks))
throw new InvalidOperationException("UserContext doesn't contain a valid SubscriptionCallback");
Console.WriteLine($"{Name}:Desired property change:");
Console.WriteLine(JsonConvert.SerializeObject(desiredProperties));
//Console.WriteLine($"{Name}:Desired property change:");
//Console.WriteLine(JsonConvert.SerializeObject(desiredProperties));
foreach (var callback in callbacks)
if (desiredProperties.Contains($"___{callback.Key}"))
@ -281,7 +284,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(new X509Certificate2(X509Certificate.CreateFromCertFile(certPath)));
Console.WriteLine($"{Name}:Added Cert: " + certPath);
//Console.WriteLine($"{Name}:Added Cert: " + certPath);
store.Close();
}
@ -299,7 +302,8 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
var genericDef = type.GetGenericTypeDefinition();
if (genericDef == typeof(Input<>)
|| genericDef == typeof(Output<>)
|| genericDef == typeof(ModuleTwin<>))
|| genericDef == typeof(ModuleTwin<>)
|| genericDef == typeof(Volume<>))
{
if (!prop.CanWrite)
throw new Exception($"{prop.Name} needs to be set dynamically, please define a setter.");
@ -314,7 +318,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
private void RegisterMethods()
{
Console.WriteLine($"{Name}:RegisterMethods called");
//Console.WriteLine($"{Name}:RegisterMethods called");
var interfaceType = GetType().GetProxyInterface();
if (interfaceType == null)
@ -328,9 +332,90 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules
internal async Task ReportTwinAsync<T>(string name, T twin)
where T : IModuleTwin
{
Console.WriteLine($"{Name}:ReportTwinAsync called");
//Console.WriteLine($"{Name}:ReportTwinAsync called");
await _ioTHubModuleClient.UpdateReportedPropertiesAsync(twin.GetReportedTwin(name).Properties.Reported);
}
internal void RegisterVolume(string volumeName)
{
var volumePath = volumeName.ToLower();
if (!Directory.Exists(volumePath))
{
var di = Directory.CreateDirectory(volumePath);
}
Volumes[volumeName] = volumePath;
}
internal T GetFileData<T>(string name, string index)
where T : class, new()
{
try
{
var path = Path.Combine(Volumes[name], index);
if (File.Exists(path))
{
var bytes = File.ReadAllBytes(path);
var result = JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(bytes));
return result;
}
}
catch (Exception ex)
{
Console.WriteLine($"{Name}:ERROR:{ex}");
}
return null;
}
internal bool SetFileData<T>(string name, string index, T value)
where T : class, new()
{
try
{
var path = Path.Combine(Volumes[name], index);
var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value));
File.WriteAllBytes(path, bytes);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"{Name}:ERROR:{ex}");
}
return false;
}
internal bool DeleteFile(string name, string index)
{
try
{
var path = Path.Combine(Volumes[name], index);
if (File.Exists(path))
File.Delete(path);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"{Name}:ERROR:{ex}");
}
return false;
}
public void Dispose()
{
if (Volumes != null)
foreach (var item in Volumes)
{
try
{
//todo:empty or not?
//if (Directory.Exists(item.Value))
// Directory.Delete(item.Value);
}
catch { }
}
}
}
}

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

@ -1,15 +1,11 @@
namespace Microsoft.Azure.IoT.TypeEdge.Modules
{
public abstract class Endpoint
public abstract class Endpoint : TypeProperty
{
protected Endpoint(string name, EdgeModule module)
:base(name, module)
{
Name = name;
Module = module;
}
public string Name { get; set; }
public abstract string RouteName { get; }
internal EdgeModule Module { get; set; }
}
}

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

@ -5,18 +5,47 @@ using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
namespace Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints
{
public class Input<T> : Endpoint
where T : IEdgeMessage
where T : class, IEdgeMessage, new()
{
private Volumes.Volume<T> _volume;
public Input(string name, EdgeModule module) :
base(name, module)
{
if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Reference<>))
{
_volume = new Volumes.Volume<T>(Name, Module);
Module.RegisterVolume(name);
}
}
public override string RouteName => $"BrokeredEndpoint(\"/modules/{Module.Name}/inputs/{Name}\")";
public virtual void Subscribe(Endpoint output, Func<T, Task<MessageResult>> handler)
{
Module.SubscribeRoute(output.Name, output.RouteName, Name, RouteName, handler);
var dereference = new Func<T, Task<MessageResult>>((t) =>
{
if (_volume != null)
{
//todo: find a typed way to do this
var fileName = typeof(T).GetProperty("FileName").GetValue(t) as string;
var referenceCount = (int)typeof(T).GetProperty("ReferenceCount").GetValue(t);
var message = _volume.Read(fileName);
if (--referenceCount <= 0)
_volume.Delete(fileName);
return handler(message);
}
else
return handler(t);
});
Module.SubscribeRoute(output.Name,
output.RouteName,
Name,
RouteName,
dereference);
}
}
}

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

@ -5,18 +5,33 @@ using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
namespace Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints
{
public class Output<T> : Endpoint
where T : IEdgeMessage
where T : class, IEdgeMessage, new()
{
private Volumes.Volume<T> _volume;
public Output(string name, EdgeModule module) :
base(name, module)
{
if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Reference<>))
{
_volume = new Volumes.Volume<T>(Name, Module);
Module.RegisterVolume(name);
}
}
public override string RouteName => $"/messages/modules/{Module.Name}/outputs/{Name}";
public async Task<PublishResult> PublishAsync(T message)
{
if (_volume != null)
{
string fileName;
if (_volume.TryWrite(message, out fileName))
{
typeof(T).GetProperty("FileName").SetValue(message, fileName);
typeof(T).GetProperty("Message").SetValue(message, null);
}
}
return await Module.PublishMessageAsync(Name, message);
}
}

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

@ -3,7 +3,7 @@
namespace Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints
{
public class Upstream<T> : Output<T>
where T : IEdgeMessage
where T : class, IEdgeMessage, new()
{
public Upstream(EdgeModule module) :
@ -14,7 +14,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints
public override string RouteName => "$upstream";
public void Subscribe<TO>(Output<TO> output)
where TO : IEdgeMessage
where TO : class, IEdgeMessage, new()
{
Module.SubscribeRoute(output.Name, output.RouteName, Name, RouteName);
}

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

@ -4,7 +4,7 @@ using System.Text;
namespace Microsoft.Azure.IoT.TypeEdge.Modules.Messages
{
public class DiagnosticsMessage : IEdgeMessage
public class DiagnosticsMessage : EdgeMessage
{
private string[] _records;
@ -12,17 +12,5 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules.Messages
{
_records = data;
}
public IDictionary<string, string> Properties { get; set; }
public byte[] GetBytes()
{
return Encoding.UTF8.GetBytes(string.Join(Environment.NewLine, _records));
}
public void SetBytes(byte[] bytes)
{
_records = Encoding.UTF8.GetString(bytes).Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
}
}
}

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

@ -1,11 +1,22 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text;
using Microsoft.Azure.IoT.TypeEdge;
namespace Microsoft.Azure.IoT.TypeEdge.Modules.Messages
{
public interface IEdgeMessage
public abstract class EdgeMessage : IEdgeMessage
{
IDictionary<string, string> Properties { get; set; }
byte[] GetBytes();
void SetBytes(byte[] bytes);
public IDictionary<string, string> Properties { get; set; }
public byte[] GetBytes()
{
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this));
}
public void SetBytes(byte[] bytes)
{
var obj = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bytes), GetType());
this.CopyFrom(obj);
}
}
}

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

@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace Microsoft.Azure.IoT.TypeEdge.Modules.Messages
{
public interface IEdgeMessage
{
IDictionary<string, string> Properties { get; set; }
byte[] GetBytes();
void SetBytes(byte[] bytes);
}
}

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

@ -3,25 +3,8 @@ using System.Text;
namespace Microsoft.Azure.IoT.TypeEdge.Modules.Messages
{
public class JsonMessage : IEdgeMessage
public class JsonMessage : EdgeMessage
{
private string _jsonData;
public JsonMessage(string data)
{
_jsonData = data;
}
public IDictionary<string, string> Properties { get; set; }
public byte[] GetBytes()
{
return Encoding.UTF8.GetBytes(_jsonData);
}
public void SetBytes(byte[] bytes)
{
_jsonData = Encoding.UTF8.GetString(bytes);
}
public string JsonData { get; set; }
}
}

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

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.Azure.IoT.TypeEdge.Modules.Messages
{
public class Reference<T> : EdgeMessage
where T : IEdgeMessage
{
public Reference()
{
ReferenceCount = 1;
}
public int ReferenceCount { get; set; }
public string FileName { get; set; }
public T Message { get; set; }
}
}

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

@ -5,6 +5,7 @@ using Microsoft.Azure.IoT.TypeEdge.Attributes;
using Microsoft.Azure.IoT.TypeEdge.Modules;
using Microsoft.Azure.IoT.TypeEdge.Modules.Endpoints;
using Microsoft.Azure.IoT.TypeEdge.Twins;
using Microsoft.Azure.IoT.TypeEdge.Volumes;
namespace Microsoft.Azure.IoT.TypeEdge.Proxy
{
@ -34,8 +35,10 @@ namespace Microsoft.Azure.IoT.TypeEdge.Proxy
if (!invocation.Method.ReturnType.IsGenericType)
return;
var genericDef = invocation.Method.ReturnType.GetGenericTypeDefinition();
if (!genericDef.IsAssignableFrom(typeof(Input<>)) && !genericDef.IsAssignableFrom(typeof(Output<>)) &&
!genericDef.IsAssignableFrom(typeof(ModuleTwin<>)))
if (!genericDef.IsAssignableFrom(typeof(Input<>)) &&
!genericDef.IsAssignableFrom(typeof(Output<>)) &&
!genericDef.IsAssignableFrom(typeof(ModuleTwin<>)) &&
!genericDef.IsAssignableFrom(typeof(Volume<>)))
return;
var value = Activator.CreateInstance(
genericDef.MakeGenericType(invocation.Method.ReturnType.GenericTypeArguments),

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

@ -75,12 +75,6 @@ namespace Microsoft.Azure.IoT.TypeEdge
break;
}
var directory = Path.GetDirectoryName(fileName);
foreach (var file in Directory.EnumerateFiles(directory))
{
Console.WriteLine(file);
}
Console.WriteLine($"{moduleName}:{fileName} does not exist. Retrying in 1 sec.");
Thread.Sleep(1000);
}

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

@ -5,17 +5,18 @@ using Microsoft.Azure.IoT.TypeEdge.Modules.Enums;
namespace Microsoft.Azure.IoT.TypeEdge.Twins
{
public class ModuleTwin<T>
public class ModuleTwin<T> : TypeProperty
where T : TypeModuleTwin, new()
{
public ModuleTwin(string name, EdgeModule module)
{
Module = module;
Name = name;
}
private object _twinLock = new object();
T _lastTwin;
private string Name { get; }
private EdgeModule Module { get; }
public T LastKnownTwin { get { lock (_twinLock) return _lastTwin; } set { lock (_twinLock) _lastTwin = value; } }
public ModuleTwin(string name, EdgeModule module)
: base(name, module)
{
}
public virtual void Subscribe(Func<T, Task<TwinResult>> handler)
{
@ -25,16 +26,21 @@ namespace Microsoft.Azure.IoT.TypeEdge.Twins
public async Task ReportAsync(T twin)
{
await Module.ReportTwinAsync(Name, twin);
LastKnownTwin = twin;
}
public Task<T> PublishAsync(T twin)
public async Task<T> PublishAsync(T twin)
{
return Module.PublishTwinAsync(Name, twin);
var t = await Module.PublishTwinAsync(Name, twin);
LastKnownTwin = t;
return t;
}
public async Task<T> GetAsync()
{
return await Module.GetTwinAsync<T>(Name);
var t = await Module.GetTwinAsync<T>(Name);
LastKnownTwin = t;
return t;
}
}
}

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

@ -8,7 +8,10 @@ namespace Microsoft.Azure.IoT.TypeEdge.Twins
{
public abstract class TypeModuleTwin : IModuleTwin
{
public Twin LastKnownTwin { get; set; }
private object _twinLock = new object();
Twin _lastTwin;
public Twin LastKnownTwin { get { lock (_twinLock) return _lastTwin; } set { lock (_twinLock) _lastTwin = value; } }
public void SetTwin(string name, Twin twin)
{
@ -18,7 +21,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Twins
var settings = new JsonSerializerSettings
{
ContractResolver = resolver,
Converters = new JsonConverter[] {new JsonFlatteningConverter(resolver)}
Converters = new JsonConverter[] { new JsonFlatteningConverter(resolver) }
};
JsonConvert.PopulateObject(twin.Properties.Desired.ToJson(), this, settings);
@ -41,7 +44,15 @@ namespace Microsoft.Azure.IoT.TypeEdge.Twins
//todo: use the json serializer here
var result = LastKnownTwin;
TwinCollection properties;
if (result == null) result = desired ? new Twin {Properties = new TwinProperties {Desired = new TwinCollection()}} : new Twin {Properties = new TwinProperties {Reported = new TwinCollection()}};
if (result == null) result = desired ?
new Twin
{
Properties = new TwinProperties { Desired = new TwinCollection() }
} :
new Twin
{
Properties = new TwinProperties { Reported = new TwinCollection() }
};
if (desired)
properties = result.Properties.Desired;

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

@ -0,0 +1,19 @@
using Microsoft.Azure.IoT.TypeEdge.Modules;
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.Azure.IoT.TypeEdge
{
public abstract class TypeProperty
{
protected TypeProperty(string name, EdgeModule module)
{
Name = name;
Module = module;
}
public string Name { get; set; }
internal EdgeModule Module { get; set; }
}
}

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

@ -0,0 +1,40 @@
using Microsoft.Azure.IoT.TypeEdge.Modules;
using Microsoft.Azure.IoT.TypeEdge.Modules.Messages;
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace Microsoft.Azure.IoT.TypeEdge.Volumes
{
public class Volume<T> : TypeProperty
where T : class, IEdgeMessage, new()
{
public Volume(string name, EdgeModule module)
: base(name, module)
{
Module.RegisterVolume(Name);
}
public bool TryWrite(T data, out string fileName)
{
var fn = $@"{DateTime.Now.Ticks}";
if (Module.SetFileData(Name, fn, data))
{
fileName = fn;
return true;
}
fileName = null;
return false;
}
public T Read(string fileName)
{
return Module.GetFileData<T>(Name, fileName);
}
public bool Delete(string fileName)
{
return Module.DeleteFile(Name, fileName);
}
}
}

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

@ -86,7 +86,7 @@ If your modules have system dependencies and you want to debug inside the contai
Alternatively, you can run your application inside the containers in command line:
docker-compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.vs.debug.yml up
docker-compose -f docker-compose.yml -f docker-compose.override.yml up
> Note: To build the docker containers, temporarily you need to [add the private NuGet feed](#feed) first.

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

@ -7,6 +7,9 @@
<add key="typeedge-feed" value="https://msblox-03.pkgs.visualstudio.com/_packaging/typeedge-feed/nuget/v3/index.json" />
</packageSources>
<packageSourceCredentials>
<typeedge-feed>
<add key="Username" value="spyrosg" />
<add key="ClearTextPassword" value="123asd!@#" />
</typeedge-feed>
</packageSourceCredentials>
</configuration>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" />
</ItemGroup>
<ItemGroup>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" />
</ItemGroup>
<ItemGroup>

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

@ -13,5 +13,6 @@
</packageManagement>
<packageSources>
<add key="RocksDB ARM" value="https://www.myget.org/F/rocksdb-native-arm/api/v3/index.json" />
<add key="SDK" value="https://www.myget.org/F/aziot-device-sdk/api/v3/index.json" />
</packageSources>
</configuration>

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

@ -15,7 +15,7 @@
<ItemGroup>
<PackageReference Include="rocksdb-native-arm" Version="5.4.6" />
<PackageReference Include="RocksDbNative" Version="5.4.6.10" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.68" />
</ItemGroup>
<ItemGroup>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.68" />
</ItemGroup>
<ItemGroup>

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

@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" />
</ItemGroup>
</Project>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.68" />
</ItemGroup>
</Project>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" />
</ItemGroup>
<ItemGroup>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" />
</ItemGroup>
<ItemGroup>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" />
<PackageReference Include="Python.Runtime" Version="2.4.64" />
</ItemGroup>

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

@ -13,6 +13,7 @@
</packageManagement>
<packageSources>
<add key="RocksDB ARM" value="https://www.myget.org/F/rocksdb-native-arm/api/v3/index.json" />
<add key="SDK" value="https://www.myget.org/F/aziot-device-sdk/api/v3/index.json" />
</packageSources>
</configuration>

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

@ -18,7 +18,7 @@
<ItemGroup>
<PackageReference Include="rocksdb-native-arm" Version="5.4.6" />
<PackageReference Include="RocksDbNative" Version="5.4.6.10" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.68" />
</ItemGroup>
<ItemGroup>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.68" />
</ItemGroup>
<ItemGroup>

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

@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" />
</ItemGroup>
</Project>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" />
</ItemGroup>
</Project>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.68" />
</ItemGroup>
</Project>

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

@ -1,49 +0,0 @@
@echo off
IF "%1"=="" GOTO HAVE_USERNAME
IF "%2"=="" GOTO HAVE_PASSWORD
if exist nuget.exe (
echo nuget.exe found
) else (
echo downloading nuget.exe from https://www.nuget.org/nuget.exe
Powershell.exe wget -outf nuget.exe https://nuget.org/nuget.exe
if not exist .\nuget.exe (
echo Error: nuget does not exist.
exit /b 1
)
)
echo Adding the private nuget packages feed "private-typeedge-feed"
nuget.exe sources Add -Name "private-typeedge-feed" -Source "https://msblox-03.pkgs.visualstudio.com/_packaging/typeedge-feed/nuget/v3/index.json" -StorePasswordInClearText -ConfigFile NuGet.Config -UserName "%1" -Password "%2"
if errorlevel 1 (
echo Failed, trying to remove an existing record first ..
echo Removing the private "private-typeedge-feed" ..
nuget.exe sources Remove -Name "private-typeedge-feed"
echo Adding the private nuget packages feed "private-typeedge-feed"
nuget.exe sources Add -Name "private-typeedge-feed" -Source "https://msblox-03.pkgs.visualstudio.com/_packaging/typeedge-feed/nuget/v3/index.json" -StorePasswordInClearText -ConfigFile NuGet.Config -UserName "%1" -Password "%2"
if errorlevel 0 (
echo Success!
)
)
if exist nuget.exe (
del nuget.exe /q
)
exit /b 0
:HAVE_USERNAME
echo Your Git credentials username is required
exit /b 1
:HAVE_PASSWORD
echo Your Git credentials password is required
exit /b 1
:exit
echo exiting..

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Host" Version="0.1.68" />
</ItemGroup>
</Project>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge" Version="0.1.68" />
</ItemGroup>
</Project>

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

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.55" />
<PackageReference Include="Microsoft.Azure.IoT.TypeEdge.Proxy" Version="0.1.68" />
</ItemGroup>
</Project>