Azure / device-simulation-dotnet

IoT Simulation service
MIT License
103 stars 73 forks source link

Question: How to use Web UI with this solution? #350

Closed alexanderbikk closed 3 years ago

alexanderbikk commented 5 years ago

Hello,

How to run Web UI from here https://github.com/Azure/pcs-simulation-webui with the current WebService?

I have configured the current solution for Docker and run on localhost. Url is http://127.0.0.1:9003 My status is: {"Name":"DeviceSimulation","Status":"ERROR:Unable to use Storage","CurrentTime":"2019-03-22T14:15:05+00:00","StartTime":"2019-03-22T14:14:49+00:00","UpTime":16,"UID":"WebService.b0168988-4af6-45d0-822e-2d1045ca9392","Properties":{"SimulationRunning":"false","PreprovisionedIoTHub":"true","ActiveDevicesCount":"0","TotalMessagesCount":"0","FailedMessagesCount":"0","MessagesPerSecond":"0.00","FailedDeviceConnectionsCount":"0","FailedDeviceTwinUpdatesCount":"0","SimulationErrorsCount":"0"},"Dependencies":{"Storage":"{\n \"IsHealthy\": true,\n \"Message\": \"Alive and well!\"\n}","PreprovisionedIoTHub":"OK"},"$metadata":{"$type":"Status;1","$uri":"/v1/status"}}

I don't know why my storage is not working. But looks like the Cosmos DB will be enough for almost all features.

Then I cloned and start UI application. The url is http://localhost:3000//

Now I'm try to create the device trough the UI. But I see the folowing request http://localhost:3000/devicesimulation-svc/v1/deviceModels and I get 404.

UPD: I have updated the variable simulationApiUrl in app.config.js but it didn't help. I still get 404. I guess because my simulator project is running in Docker and I can not connect from localhost to Docker NAT. I'm not very familiar with Docker.

Now I'm trying to run the UI project in Docker but I can not find the guide

What am doing wrong? Thanks in advance

peterfelts commented 5 years ago

You'll also need the Storage Adapter service running locally in order to view and use device model definitions. Without the Storage Adapter, Simulation will not have access to any device models.

As for the issue that you're seeing with the web UI, you'll need to change the URLs in app.config.js when running locally. Here is what I use when running locally:

simulationApiUrl: 'http://localhost:9003/v1/', diagnosticsApiUrl: '/diagnostics-svc/v1/', configApiUrl: '/config-svc/v1/', iotHubManagerApiUrl: '/iothubmanager-svc/v1/',`

Note that I only change the path to the Simulation service as diagnostics, config and iotHubManagerApiUrl are not strictly needed in order to run the UI. Although, without the iotHubManager service running you won't see IoT Hub charts in the UI.

andrewschmidt-a commented 5 years ago

I had an issue with the Consistency level of Cosmos. That may be causing issues. This project expects a Strong Consistency.

peterfelts commented 5 years ago

@alexanderbikk, were you able to get the web UI running locally?

alexanderbikk commented 5 years ago

Hello @peterfelts Sorry for the late reply, I worked with other tasks. Thanks for your answer.

I tried to start the simulator using docker and I didn't started the Storage adapter since I found the docker-compose.yml file in device-simulation solution which includes the storage adapter. I decided that when I'm using Docker I need only run this compose file and 2 microservices will be started (device + storage).

Now I am trying to do it on localhost without Docker. I started up both device and storage microservices. Btw the azure storage connection string (import_storage_account_connstring) is also required but I didn't see it in documentation.

My statuses: device http://localhost:9003/v1/status {"Name":"DeviceSimulation","Status":"OK:Alive and well","CurrentTime":"2019-05-02T09:09:05+00:00","StartTime":"2019-05-02T09:08:41+00:00","UpTime":24,"UID":"WebService.43110094-d444-47ea-ac99-442b596fbc9c","Properties":{"SimulationRunning":"unknown","PreprovisionedIoTHub":"true"},"Dependencies":{"Storage":"OK:Alive and well","PreprovisionedIoTHub":"OK"},"$metadata":{"$type":"Status;1","$uri":"/v1/status"}}

storage http://localhost:9022/v1/status {"Name":"StorageAdapter","Status":"OK:Alive and well","CurrentTime":"2019-05-02T09:00:11+00:00","StartTime":"2019-05-02T09:00:09+00:00","UpTime":2,"UID":"WebService.2a469385-6784-4954-8153-80563337ef66","Properties":{},"Dependencies":{},"$metadata":{"$type":"Status;1","$uri":"/v1/status"}}

Then I try to use the web UI. Btw I changed the api url even in first try.

But now I still get 404 Here is my request ScreenClip

But when I go to http://localhost:9003/v1/deviceModels I see the response in my browser for example, so my microservice is working.

Here is the part of response: {"Items":[{"ETag":"","Id":"chiller-01","Version":"0.0.1","Name":"Chiller","Description":"Chiller with external temperature, humidity and pressure sensors.","Protocol":"AMQP","Type":"Stock","Simulation":{"InitialState":{"online":true,"temperature":75.0,"temperature_unit":"F","humidity":70.0,"humidity_unit":"%","pressure":150.0,"pressure_unit":"psig","simulation_state":"normal_pressure"},"Interval":"00:00:10","Scripts":[{"Type":"javascript","Path":"chiller-01-state.js"}]},"Properties":{"Type":"Chiller","Firmware":"1.0","Model":"CH101","Location":"Building 2","Latitude":47.640792,"Longitude":-122.126258},"Telemetry":[{"Interval":"00:00:10","MessageTemplate":"{\"temperature\":${temperature},\"temperature_unit\":\"${temperature_unit}\",\"humidity\":${humidity},\"humidity_unit\":\"${humidity_unit}\",\"pressure\":${pressure},\"pressure_unit\":\"${pressure_unit}\"}","MessageSchema" ....

The problem is that my Web UI have no access to device API I can not understand the issue, can you help me?

UPD1 Looks like problems with this endpoint http://localhost:9003/v1/simulations {"Message":"An error has occurred.","ExceptionMessage":"Missing or invalid Cosmos DB SQL connection string (^AccountEndpoint=(?.);AccountKey=(?.);$)","ExceptionType":"Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Exceptions.InvalidConfigurationException"}

But how this possible when the status is OK and the DB created in my Cosmos DB account?

UPD2 I have fixed this by adding the Cosmos DB connection string in all places where it defined in appsettings.ini So now I get this result http://localhost:9003/v1/simulations {"Items":[],"$metadata":{"$type":"SimulationList;1","$uri":"/v1/simulations"}} And 2 DBs in Cosmos DB pcs-storage and devicesimulation

But my web UI still have no access to the microservice, looks like this is configuration issue but I don't understand what I missed.

UPD3 Finally I did it! After investigation I found the "PCS_CORS_WHITELIST" variable and try to set the: "{ 'origins': [''], 'methods': [''], 'headers': ['*'] }" value recommended in appsettings.ini. And it works. Now my web Ui can access to the device microservice. But I don't' understand why it missed in documentation.

The next challenge to run device and storage microservices in Docker and connect web UI. Because always using VS is not the best solution for me

alexanderbikk commented 5 years ago

Hi @andrewschmidt-a Thanks for help. But I faced with this issue and fixed it before wrote the comment. :)

alexanderbikk commented 5 years ago

Hi @peterfelts

After all I still have problems with simulation I created my device model and created simulation using this device model and pre-provisioned IoT Hub But nothing happened and I didn't get the messages in IoT hub. ScreenClip  4

I also tried to set the IoT hub connection string manually

UPD1 Looks like I have the same problem https://github.com/Azure/device-simulation-dotnet/issues/315

UPD2 I investigated the simulation flow and see that my simulation saved properly but the task didn't started because of my devices is not connected https://github.com/Azure/device-simulation-dotnet/blob/master/SimulationAgent/DeviceTelemetry/DeviceTelemetryActor.cs#L173 I got false result in this line

At now I don't understand why this happened because I can created my custom device through the Web UI. So, I guess everything is ok with my connection string.

peterfelts commented 5 years ago

Hi @alexanderbikk

Sorry for not getting back to you earlier. So what I understand now is that your situation is:

Is this correct?

Would you please set the log level to 'debug' for the Simulation service, rebuild, run the scenario again and then attach the logs?

P.S. The error above, about iothubsearch, is not critical for the Simulation service to run. That error indicates that the UI can't find a local copy of the iothubsearch service, which is expected. This service is used to show a visualization in the web UI about the simulation, but this is not strictly needed in order to run a simulation locally.

alexanderbikk commented 5 years ago

Hi @peterfelts

Thanks, for the answer.

Yes this is correct,

I started the microservices again with already configured simulation. The simulation has status "Running" but no messages in IoT Hub. Here the log after ~10 minutes processing. log.txt

Btw, I tried to use Docker and runned images from device-simulation.sln. Those builds worked with portal but when I tried to create the simulation I got the infinite loading. But also I saw messages in my Iot Hub. However I see that the version in Docker is obsolete(or even just for testing) and used old Cosmos DB database pcs-storage.

alexanderbikk commented 5 years ago

Hi @peterfelts

Any thoughts? :)

peterfelts commented 5 years ago

Sorry, again, for going dark. I see this in the log file that you sent me:

[ERROR][2019-05-21 08:48:14.846][WebService.985ce6e8-61a4-4fdc-91d7-938af7307c3a][SendTelemetry.cs:138:SendTelemetryMessageAsync] Unexpected error while sending telemetry, {"timeSpentMsecs":0,"deviceId":"177251c2-44a8-4649-849b-ab8ae83adb30.1ff9530b-9dd4-4c40-beae-492457421874.1","e":{"ExceptionFullName":"System.NullReferenceException","ExceptionMessage":"Object reference not set to an instance of an object.","StackTrace":" at Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceTelemetry.SendTelemetry.SendTelemetryMessageAsync(String msg) in D:\\Work\\IoT\\DeviceEmulator\\device-simulation-dotnet\\SimulationAgent\\DeviceTelemetry\\SendTelemetry.cs:line 87","Source":"Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent","Data":{},"InnerException":null}}

It looks like something on that line is null. Can you set a breakpoint on that line and see what it is?

If you're using a custom device model, make sure that it includes a schema for the custom message, along the lines of what you can see here.

alexanderbikk commented 5 years ago

Hello, np

Thanks a lot.

I can do it after 4-5 hours. I will send feedback as soon as possible. I really hope we can fix it today :)

Have a nice day!

alexanderbikk commented 5 years ago

Hi @peterfelts

I see that DeviceClient is null image Looks like it should be initialized in DeviceTelemetryActor from deviceContext

alexanderbikk commented 5 years ago

I am trying to understand where the Client is initialize.

I see that even after deviceContext.Init() method(in CreateActorsForDevice method) the Client still null image

Then we put this context in deviceTelemetryActor

Looks like that the Client of diveceContext instance initialized in RunAsync method of Connect class. And it happens before we create the deviceActor I guess... But this code was never called for me. image

I am going to re-create the simulation with default device and try to check will the code where the Client initialized called at least once.

alexanderbikk commented 5 years ago

As far as I understand the Client is null because the connection was never called image My device has no status ReadyToConnect

Even more, as I mentioned earlier my devicecontext was never in Connected case image

So, I just comment this line, and that's why the worker is working but I get this error since the connection was never established. But now I don't understand why my device not in Connected state.

So, the main problem is that the worker never started his work, because the diviceContet doesn't have tatus connected. Sorry, I really forgot that I commented this line to see what happens if I skip the connected status

UPD1 Finally I see that my status is not Connected because the RunAsync method of Connect class is not called The RunAsync method of Connect called only if my device has status ReadyToConnect. I found the RedyToConnect status only in method ScheduleConnection of DeviceConnectionActor class And finally the ScheduleConnection method called in HandleEvent in some cases(need to investigate) also in DeviceConnectionActor class.

So the main question is why ScheduleConnection is not called and the Client connection is not established

UPD2 Btw, as I mentioned earlier when I try to run all using Docker (docker-compose.yml in solution). My simulation is working and I see the telemetry flow in my IoT Hub. But unfortunately the UI not working properly with version of pcs-storage-adapter-dotnet that provided in docker file. And I don't see my simulations in UI. That's why I think all should be ok with my IoT hub connection and etc

peterfelts commented 5 years ago

Hi there,

In the SimulationAgent (SimulationAgent\Agent.cs), there is a method called TryToStartThreads(). TryToStartThreads calls RunAsync on each of the main threads (connection, telemetry, etc.).

It passes a list of device actors which are created in the SimulationManager SimulationManager.cs.

When each deviceConnectionActor is initialized, it's initial status is set to ReadyToStart.

Once the connection thread gets going, it starts asking each connection actor if it has work to do HasWorkToDo(). HasWorkToDo will return true unless the device hasn't been (or failed to) authenticated (ReadyToRegister) or has been throttled by the hub (WaitingForDeviceQuota), or, finally, the Simulation code has determined that too many messages have been sent (DeviceQuotaExceeded, et. al.).

I see in the image above that the implementation of HasWorkToDo that you're looking at is not what is in Master

Perhaps that's the problem?

alexanderbikk commented 5 years ago

Hi @peterfelts No I guess it's not the problem I have the latest version. My HasWorkToDo() in the image above in DeviceTelemetryActor class not in DeviceConnectionActor class. And the problem is that in this line I got "false". So the HasWorkToDo() method doesn't start the simulation because the deviceContext is not connected for some reason.

Why this can happen?