Click here to Skip to main content
15,946,342 members
Articles / Internet of Things

Azure IoT Central Tester

Rate me:
Please Sign up or sign in to vote.
5.00/5 (5 votes)
17 Jan 2022CPOL26 min read 10.9K   138   5   5
Design and implementation of small tool, tester for Azure IoT Central
This article describes the design and implementation of the small tool, tester for exploring Azure IoT Central with Android Phone as a virtual Plug and Play Device (PnP Device).

Image 1

Image 2

Contents

Features

  • Android IoT Device simulator for Azure IoT Hub and Azure IoT Central
  • Plug and Play Device model DTDL version 2
  • Sending simulated telemetry data
  • Re-sending a device telemetry data with an original timestamp
  • IoT connectivity using the QR code
  • Capability to provision and connect a new device with assigning its PnP model
  • MQTT v3.1.1 protocol on port 8883
  • Using the MQTT protocol directly based on the MSDN Doc
  • No Device SDK
  • Using M2Mqtt - MQTT Client library for .NET

Introduction

Five years ago, I posted a little desktop tool called Azure IoT Hub Tester for simulation of the IoT devices connected to the Azure IoT Hub and later to the Azure IoT Central. Based on that and while moving to the Plug and Play device model (the conceptual point of the Azure IoT Central App), I can say that this article and its implementation is a natural extension to the tool Azure IoT Hub Tester for Android devices.

As the name of the article suggests, this implementation has focused on the Azure IoT Central platform, but it can also work with an Azure IoT Hub and/or without the device template model.

The following screen snippet shows a position of the IoTPnP Device such as an Android implementation of this article in the Azure IoT Central. Basically, the IoTPnP app is a MQTT device, which can be provisioned and/or connected to the Azure IoT Central App, including its device template as a sharable resource between them located in the well known repository of IoT models.

Image 3

The IoTPnP device represents a fully transparent device to the real device connected to the Azure IoT Central using the same device model like a real device, can send manual telemetry data, device twin such as the readonly and writable properties, handle a direct method (command) and read the cloud-to-device messages. In other words, the IoTPnP device has implemented all features required for simulation of the plug and play device model.

Besides that, the IoTPnP device can obtain a time specific batch of telemetry data for any connected device and re-send them again with an original timestamp. Note that any payload for publishing by IoTPnP device can be edited manually or randomly updated based on the needs.

The IoTPnP device can be connected to the Azure IoT Hub/Central using the QR code containing necessary properties for creating a device connection string or just straight a standard text of the device connection string. Note, that all important config properties, states, etc. of the IoTPnP app are cached, so the application can be closed, minimized, etc. and reopen again with the cached config properties.

OK, let's describe the concept and design. I am assuming you have some knowledge of the Azure IoT Infrastructure, Azure IoT Central and working experience with my Azure IoT Hub Tester tool.

Concept and Design

The concept and design of Azure IoT Central Tester and its Android implementation is driven by a device template model, the same way like it is done in the Azure IoT Central. The device model defines interactions between both ends such as the device and application. The device capabilities are grouped into the interfaces described by the collection of the properties (readonly and writable), telemetry (D2C messages) and commands (sync and queued/C2D messages). The interfaces can be packaged into the component and reused across others device models and/or multiple times within the same device model, see the device model dtmi:com:example:TemperatureController;2, where the device model contains two thermostats with the same capabilities.

Based on the above concept, the design of the Azure IoT Central Tester is driven by component, so the IoTPnP device interacts with an Azure IoT Central only by capability of the selected component. The special case is if the device model has an interface in the root model, which is known as a default component.

So, as the above, the capability of the device is described by the following: telemetry, properties and command. The navigation between them is very simple like it is shown in the following screen snippets:

Image 4

As you can see, above is the main page of the IoTPnP app, where on the top is the application bar for displaying a device name, selected device model and its component and the icon of the IoT connectivity status (green/red). Below this toolbar is the navigation bar for interface capabilities. Each selected navigation menu can be extended by clicking an optional menu on the right side of the app bar. The first four items of the navigation bar are related to the selected model component, the last one, on the right side has the name Model/Log and it is used for managing and logging IoTPnP application. Selecting this item and its settings option menu, we can handle IoT Connectivity, Device template, etc. More details about this will be described later on in the article.

The layout below the navigation bar is horizontally scrollable (except of the Model/Log item) like it is shown in the following screen snippets:

Image 5

Basically, the second horizontal page is used for switching between the Subscriber and Publisher rsp. Model (Request) and Response. Note, that the Subscriber represents a readonly page where received message payload is displayed (from the Azure Iot Hub/Central). The other one, such as Publisher page represents a payload for publishing message on the shown topic. This page can be edited. Also, you can see on the bottom right side, there is a flat button to publish the page contents.

The following screen snippets show the Model item with selecting a Settings option menu:

Image 6

OK, it's show time. Let's describe what this tiny tool can do for you. I am assuming you have some knowledge of the Azure IoT Hub/Central.

Usage

Before you start using the Azure IoT Central Tester, I am assuming you already have the Azure IoT Central Application. Note, that the tool will still work for features, where device connectivity to the Azure IoT Central App is not required, such as access to the PnP Models repository, etc.

Note, that this article has been written using the free trial for 7 days IoT Central Application - rk2021iotcfree, so all QR codes are expired.

The following screen snippet shows a main page of the IoTPnP app on the Android phone, after clicking on the launcher icon:

Image 7

The major part of the tool, which is representing a virtual MQTT device is its connectivity to the Azure IoT Central rsp. to the Azure IoT Hub. Basically, the IoT device is connected based on the device connection string. In the case of the Azure IoT Hub, we have available device connection string or we can very simply create one from the Azure IoT Hub Shared access policies. The other one, such as the Azure IoT Central App, we don't have a direct access to its underlying Azure IoT Hub. We must use a Device Provisioning Service (DPS), see more details about its REST APIs here.

The Azure IoT Central Tester supports only SAS token for device iot connectivity using:

  • Device Provisioning Service
  • Device connection string

The following steps show in detail how our virtual MQTT device (such as an android app IoTPnP) can be connected to the Azure IoT providers.

One more thing you should be aware of, that the device model represents a device implementation and its capabilities, so while the device is provisioning and connecting, this model id is passed to the IoT provider. In other words, based on this device modelId, the Azure IoT Central app will assign or re-assign the device template for connected device(s) in the app.

Therefore, if we don't know about the assigned device template for the specific device, the tool should use the none device model during the device provisioning and then after connectivity, we can select one based on the needs.

1. Connecting to the Azure IoT Central - Provisioned Device

This is the most common way for a device connectivity to the Azure IoT Central, where the app has already registered a device and assigned its device model for message data exchange.

The following screen snippet shows my rk2021iotcfree application with all devices:

Image 8

As you can see, the device1 is provisioned and interacted based on the IoT Plug and Play mobile model.

Let's connect our tool to this application as a device represented and interacted as a device1, so select this device and click on the Connect and then select QR code:

Image 9

The Device connection QR code represents a JSON object with the following schema:

JSON
{
 "scopeId":"0ne00461860", 
 "deviceId":"device1",     
 "deviceKey":"..."
}

I have tried to discuss with an Azure IoT Central team to add one additional optional property, such as a modelId of the assigned device template, see this discussion here.

Note that this tool can accept this optional modelId property and based on that, the IoTPnP app can reselected, so both IoT ends are in the sync for their message data exchange interaction. It's up to you, to generate this optional device connection QR code using some 3rd party free tool, for instance QR Code Generator for Windows 10 by Snake Chia Labs.

OK, let's continue in our step to connect our tool with an Azure IoT Central as a provisioned device1. This end is ready for scanning the device connection QR code.

The following screen snippets show how the IoTPnP app can be connected. Select the Model(Log) item in the navigation bar, then options menu Settings:

Image 10

In the above menu, select the IoT Connection and you should get the phone scanner. Use the scanner for scanning a device connection QR code from your Azure IoT Central App screen. After a short vibration, you will see the JSON object from the QR code in the dialog, see the following screen snippet:

Image 11

Pressing the OK button, the IoTPnP app will start processing the device provisioning service with your IoT application defined by scopeId. Note, that this process takes some time and its successful result will show up in log and in the App bar, see the following screen snippet:

Image 12

At this moment, we have our tool connected to the Azure IoT Central app, but we don't know anything about the message data exchange, how both IoT ends are going to interact. In other words, sending some telemetry data will show up as _unmodeleddata, so we have to obtain an assigned modelId of the provisioned device for assigned on the device side.

There is no direct support built-in the Azure IoT Central to get the modelId assigned for specific device, we have to use multiple REST APIs calls and query the device template to get it. It looks like the Azure IoT Central team doesn't respect a device model driven architecture and they are using their own internal device template architecture with a different unique id.

This fact makes it difficult to query some sharable interfaces across multiple device template instances, etc.

Anyway, following are the steps of how to obtain a modelId from the Azure IoT Central App. First of all, we have to generate an API Token and scan it by out tool for authorization header of the REST APIs:

The following screen snippet shows the QR code of the API token generated by Azure IoT Central App:

Image 13

Now, on the device side, select the Model(Log)/Show device template to get the tool scanner:

Image 14

After scanning and vibration, the dialog will show an ApiToken, see the example on the following screen snippet:

Image 15

Pressing the OK button, will start multiple REST calls to the Azure IoT Central App to figure out a device modelId used for device1.

The result of this process is the log message where we can see assigned device model at the Azure IoT Central App for the specific device1. Note, that this modelId is added to the cached list of the device models used by our tool:

Image 16

1a. Get the Device Model from Repository

This step demonstrates how we can select a device model from the Repository. The entry point in our tool is Model(Log)/Settings/Device Template, see the following screen snippets:

Image 17

You will get the dialog list of models already used by the tool. You have the following options in the dialog: clicking on the specific item, removing from the list by holding the specific item, pressing the Add button to add new one or just Cancel the dialog.

Note, there is a special none item in the list, which is unassigning a model from the device, in other words, none device model is assigned to the device.

The following screen snippet shows the result when the dtmi:azureiot:PhoneAsADevice;2 has been selected:

Image 18

Now, the IoTPnP virtual device with a capability of the device1 is ready to interact with connected Azure IoT Central App.

The following steps demonstrate other ways of how the IoTPnP virtual device can be connected to the IoT provider.

2. Create a New Device With a Device Model Assigning

This step demonstrates how to provision a new device, including its assigned model. The Azure IoT Central doesn't have (for this kind of device connectivity) built-in the QR code, so we have to create one. Basically, the QR code contains an application scopeId and primary/secondary key of the Shared access signature. This information can be found in the Azure IoT Central, see the following screen snippet:

Image 19

For generating a QR code for this JSON schema, we can use any free 3rd party program, like is shown in the following screen snippet:

Image 20

JSON
{
 "scopeId":"0ne00461860",      
 "deviceKey":"..."
}

Now, we need to start the scanner for IoT Connection, so select this menu like it is shown on the following screen snippet. Note, if the previous connection has been cached, you have to press the Cancel to clean it up and start over to bring up the phone scanner.

Image 21

The prompt dialog shows the JSON object with required properties for DPS process, by pressing the OK button, you will be asked to type the device Id. Note, that the id must be in lowercase characters. I do recommend selecting the device model prior to this DPS process, so it can be passed to the Azure IoT Central for assigning to the device on the consumer side.

Image 22

The following screen snippet shows the result, when the device1000 is in the collection of the connected devices:

Image 23

Now, the IoTPnP device is ready to interact with connected Azure IoT Central App.

3. Using the Device Connection String

This step demonstrates how device connection string can be used to establish a connection to the Azure IoT Hub/Central.

The following screen shows a 3rd party generator of QR code for this text:

Image 24

Recently, my Azure IoT Hub tester has been updated, so we can get a QR code of the device connection in the Log contents when the Copy ConnectionString is selected:

Image 25

By scanning the device connection string, QR code will pop up the following dialog and pressing the OK button will create a connectivity to the Azure IoT Hub/Central:

Image 26

Now, the IoTPnP device is ready to interact with connected Azure IoT Central App.

4. Device Disconnecting/Reconnecting

This step demonstrates how we can disconnect or reconnect a device. The long click on the App bar will popup the menu for these features:

Image 27

Image 28

5. IoT Device Model Simulation

This step demonstrates the usage of the device model for interaction and message exchange patterns between the IoT ends such as this tool as a virtual device and connected application represented by the Azure IoT Central App.

Following the device model architecture where the device capabilities such as the telemetry, properties and commands are described in the device interface. Collection of the interfaces can be grouped into the reusable components. The special case of the device model is the model with a simple interface "hosted" in the model itself known as a root component or a default component.

The device, which is using the device model for interaction with the connected IoT application is known as a Plug and Play (PnP) device, that is upcoming name of our Android virtual app such as IoTPnP.

The device model (written by spec DTDL v2) represents a message exchange pattern between the IoT producer and its consumer. This is a common contract document stored in the shareable repository of models.

The PnP device model enables building an IoT solution using the Model First strategy the same way as we have a Contract First.

This article and its PnP device Android implementation is trying to demonstrate the Model First strategy, where the device side can interact with the iot application without the real implementation in the full transparent manner.

One more thing, IoTPnP device allows to simulate random numeric value based on the type value. Basically, the payload for publisher is based on the device model schema and the value is represented by a string with a prefix '$' character, for instance:

JSON
{
  "battery":"$integer",
  "accelerometer":{
    "x":"$double",
    "y":"$double",
    "z":"$double"
  }
}

Before publishing a payload, these aliases of values are replaced by random value based on the type. Note, that only a string type is not randomized and its value is always abcd.

The following steps are described in the details how IoTPnP device can interact with the connected IoT application based on the selected device model:

5a. Telemetry data (D2C Message)

This step demonstrates how we can send the telemetry data for selected component based on the device model to the IoT application.

The App bar of our tool shows three ids such as:

  • deviceId: mobile1
  • device display model name: IoT Plug and Play mobile
  • Component name: sensors

Clicking on the Telemetry item of the navigation bar, we are in the place for publishing a payload on the topic, see the following screen snippet:

Image 29

As you can see above, the model component sensors have a capability to publish telemetry data, left scrolling the page will show the end of the topic, where is a property $.sub=sensors indicates the component name.

The payload can be edited, or its values updated randomly, see the following screen snippet after selecting Edit on the context menu:

Image 30

and selecting an Update random:

Image 31

Note, if you want to go back to the original payload, just select a menu item Telemetry. on the navigation bar.

So, now we are ready to Publish the payload as a telemetry data. In my demonstration example, I have clicked three times on the Publisher button, as you can see in the following screen snippet:

Image 32

Let's look at the other side such as the Azure IoT Central App. The following screen snippet shows received Raw data:

Image 33

That's great. We can see that the telemetry data has been accepted by Azure IoT Central App based on the common device model.

5aa. Getting the Raw Telemetry Data from the Azure IoT Central

The IoTPnP device has a feature to obtain a stream of telemetry data for specific device including the original timestamp. The following steps show how we can get back our published telemetry data on the device mobil1. This feature requires a valid ApiToken, otherwise we have to scan its QR code. I am assuming we have a valid ApiToken, so we can press the OK button:

Image 34

We need select a device mobil1 and then the TimeWindow:

Image 35

The following screen snippet shows a result of this operation. Note, that the process will take same time, as it requires to process the multiple REST calls:

Image 36

Also, we can see some details about this process within the Model/Log page:

Image 37

That's all for the demonstration of the publishing a telemetry data.

One more thing. Remember this step 5aa for later discussion, when I will demonstrate the telemetry data batching, the feature for re-sending telemetry data from the real device.

5b. Readonly/Writable Properties (Reported/Desired Properties)

This step demonstrates how the device interacts with an Azure IoT Central for interface capability such as properties. I am assuming you have knowledge of the Azure IoT Central, Azure IoT Hub Device Twin and device PnP Model.

The device model contains basically two kinds of properties related to the IoT application end (Azure IoT Central App) such as writable and readonly properties. The IoT application can change only the writable properties. From the device facing side, these properties are in the opposite capability, so the device can readonly a writeable property, so on.

This characteristic is coming from the Azure IoT Hub Device Twin represented by reported and desired properties.

Capability to synchronize both IoT ends can be reached using a device twin such as the reported (readonly) and desired (writable) properties. The properties are event driven, so if their value has been changed, the IoT ends (device and IoT app) can receive these changes. This is very important behavior to simplify by synchronizations of the states between both ends.

Based on the above short description, the IoTPnP device implements the feature Twin, see the following entry point:

Image 38

As you can see above, there are two hardcoded folders such as:

  • /PATCH/properties/desired/#
  • /res/#

These two folders represent two topics for subscribing (receiving) the MQTT messages from the IoT App. The first one is dedicated for receiving changes on the desired (writable) properties and the second one is for receiving a result of the publish request, for instance: Get the full device twin from the backend (IoT app).

From the device model point of the view, the first folder is related to the writable properties and the second one for readonly properties.

Note, if the component of the device model contains readonly and/or writable properties, the names of the folder are bolded.

As you can see above, the component sensors do not have any Readonly or Writable properties.

One more thing, every time when the item Twin on the navigation bar is clicked, the IoTPnP device is publishing request to get the device Twin from the IoT App, so when we select the Subscriber Tab, the page will show a present state of the desired and reported properties.

The following screen snippet shows an empty payload for publishing. We can publish some property to the IoT App, but this property is going to handle as _unmodeleddata.

Image 39

So, let's change the component for simulation where we have some properties. Click on the Model/Settings and select the Component Template. The device model offers the two other components such as the device_info and default (root component). Let's select the device_info component:

Image 40

Clicking on the Twin navigation item, we can see the following differences in the Publisher Tab:

Image 41

Clicking on the Subscriber Tab, we can see the current values of the device twin (reported and desired properties):

Image 42

By the way, the above device_info state is done from the real mobile.

The following screen snippets show simulation (publishing) any unmodeled properties on both IoT Ends (device and IoT Central):

Image 43

Image 44

Back to our device_info readonly properties and we are going to publish random values to the IoT App:

Image 45

Clicking on the Twin, we can refresh the Subscriber Tab page:

Image 46

On the Azure IoT Central, we can see this update:

Image 47

Let's select the last component such as a default component. We can see, there is a simple one property readOnlyProp. Pressing the Publish button, the randomly updated property is sent to the Azure IoT Central:

Image 48

You can see in the following screen snippet the value of the readOnlyProp:

Image 49

That's great, it is working well between these IoT ends based on the device model.

5ba. Message Exchange for Writable Property

Our device model has one writable property as it is shown in the following picture. Let's update its value for XYZ. Clicking the Save button, the event is generated and sent to the device:

Image 50

The following screen snippet shows received PATCH for this writable property and the Publisher Tab shows a format of the respond payload for this patch. Note, that the IoT Central continues waiting for acknowledge of this state from the device side:

Image 51

We can click on the Publisher page to bring the Edit mode, acknowledge the property value and its version. The correct values are shown on a Subscriber page:

Image 52

When the Publisher has been hit, the payload is sent to the Azure IoT Central and we can see the acknowledge state on the screen:

Image 53

So, now we know both IoT ends have synchronized the writable property.

Clicking on the Twin navigation item, we can see the latest state of the device twin:

Image 54

That's all for simulation of the device model properties.

5c. Commands (Direct Methods)

The device model used a command type for invoking a device behavior. The command message exchange pattern between the IoT App and device basically uses a request/response pattern, following the Azure IoT Hub Device Direct Method such as a synchronous call.

The command always requires a response from the device method. The invoker informs the device about the waiting time (responseTimeoutInSeconds) for a response message and in the case of long running command, the device can respond immediately with a status 202 accepted, otherwise the command failed if the time expired.

The following steps demonstrate an interaction of the command in the sensors component. Note, that the invoker of the command is not a device, it is an IoT App.

The following screen snippets show a situation before invoking a commnad at both IoT ends, such as an Azure IoT Central and next picture on the device:

Image 55

Image 56

As you can see above, by clicking on the Methods, we can see all methods defined in the specific component, that is the bolded name of the folder, where we can see the received request/response messages. Selecting the name of the command, the model of the request and response will show up on the horizontal scrollable page.

Let's make a command. The following screen snippet shows a selected command on the Azure IoT Central:

Image 57

Pressing the above Run button, the request message is sent to the device:

Image 58

At this time, I was busy making the snippet for this request, so the responseTimeoutInSeconds (30sec) has expired and invoker finished this command with a Failed status, see the command history:

Image 59

Therefore, I made one more command with focusing on the immediate respond, such as publishing an empty payload:

Image 60

As you can see, the following history of the command, we were successful in this interactions:

Image 61

That's all for this sync(online) command which always requires a respond from the device, but there is one more command handled by IoT App explicitly, in other words, it is not defined by the device model. This command is processed offline and it is useful for disconnectable devices.

One more thing for this sync commands, the following screen snippet shows how we can start a long-running command. Clicking on the Accepted (202) item, we are accepting this command and the finally response will be used by sending a reported property with the name of the method:

Image 62

5d. Queued/offline Commands (C2D Messages)

This command is known as a cloud-to-device messaging (C2D Messaging). More details about the offline command can be found here.

Our demonstrated model doesn't have an offline command, see the following screen snippet when we click on the Messages item:

Image 63

Let's change the online (standard) command to the offline (queued) one. The following screen snippet shows how it can be done in the Azure IoT Central. Please, don't forget press the Save button and then click on the Publish to refresh this change in the application:

Image 64

Now, we have an offline command, let's invoke it:

Image 65

Clicking on the above Run button, the C2D Message is sent to the device. We can see the no-bolded folder for this command and its received message:

Image 66

Note, the above picture shows a message payload, but by horizontally scrolling this page, we can see all properties on the topic, including the method name.

The offline command sent the message to the queue of the underlying IoT Hub of the IoT Central App, so the respond is immediate, and it finished with a success state:

Image 67

6. Advanced Features

Currently, the IoTPnP app has built-in only one advanced feature such as batching telemetry data which allows to replay already published telemetry data from the device. The batching telemetry data includes the original timestamp using the well-known properties, the _eventcreationtime.

6a. Batching Telemetry Data

This step demonstrates batching telemetry data of the real device mobil1 and published by device device1. First of all, we have to connect our IoTPnP device as a device1 and then selecting a Download Sample1 option:

Image 68

Next, we need to select a device and the TimeWindow for batching telemetry data:

Image 69

The telemetry data from the selected device and the TimeWindow will be show up in the Publisher page of the device1. Pressing on the Publisher button, the Batching process kicked off:

Image 70

Note, that the Azure IoT Central currently doesn't support publishing telemetry data in the batch, where each event can have its own timestamp (_eventcreationtime), we have to do it in the batch loop one by one.

The following screen snippet shows a Model/Log page after the batch process finished:

Image 71

The Raw data of the batching telemetry data is shown in the following screen snippet of the IoT Central:

Image 72

As you can see in the above, the device model accepted a property _eventcretiontime.

That's all for the batching process.

Implementation

First of all, the following are the prerequisites:

  • Visual Studio 2019/2022
  • M2Mqtt - MQTT Client Library for .NET version 4.3.0
  • Microsoft Azure IoT Central Application (any tier, included a Free)
  • Connectivity to the Internet
  • Downloading package (source) for this article (option for creating .apk)
  • Understand document Overview of Android development on Windows

The Android app project has been created from the Simple View App template as a starting point. The assembly name and namespace is simple as App6, the application name is IoTPnP and the package name is com.pathcom.rkiss.IoTPnP. Many parts of the code have been used from my proven article Azure IoT Hub Tester, for instance: PnP Model library, sasToken library, etc. and of course, thanks to 3rd parties such as the MQTT communication client library M2Mqtt and ZXing.Mobile for QR scanner.

The Android app is a MainActivity driven app with the handlers, eventing and dialogs triggered by menu items in the navigation bar, options menu or context menu on the page. The multithreading coding is based on the ThreadPool.QueueUserWorkItem method and async/await pattern.

The following screen snippet (no code snippet) shows an example of the multithreading implementation usage in the background task of the dialogs, where the https communication is required and the workflow process is depended on the dialog select:

Image 73

The above is a small code fragment from the MainActivity.cs implementation file. Please have a look at it, if you are interested in how this Android app has been implemented.

That's all for this article, I hope you enjoyed it.

Conclusion

This article gives to you a tiny mobile tester for Azure IoT Central App or Azure IoT Hub. It can be your helper while evaluating and exploring the Azure IoT Central App, for developing MQTT Devices, troubleshooting an IoT Data, or simulation of the telemetry data from the real device. One more thing, this mobile tiny tester interacts with the IoT Central as a Plug and Play device, it allows to simulate the telemetry, properties and commands of the device capabilities. I hope you will find it useful.

References

History

  • 17th January, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMessage Closed Pin
5-Apr-22 17:53
Korey Volkman5-Apr-22 17:53 
GeneralMy vote of 5 Pin
JimCoffell27-Jan-22 0:26
professionalJimCoffell27-Jan-22 0:26 
GeneralRe: My vote of 5 Pin
Roman Kiss27-Jan-22 2:42
Roman Kiss27-Jan-22 2:42 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA19-Jan-22 4:40
professionalȘtefan-Mihai MOGA19-Jan-22 4:40 
GeneralRe: My vote of 5 Pin
Roman Kiss19-Jan-22 6:00
Roman Kiss19-Jan-22 6:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.