Controlling Industrial LED Lighting via ESP8266

I am attempting to write an Arduino code for my ESP8266 (ESP-12E) to function as a PWM generator for LED lighting brightness control. This of course is something I have never done before and there is little information on how to make this function correctly with Losant.

As I understand it, I must make a workflow in order to send a command to update the light level. I can find the “Device: Command” block in the workflow but am unsure how it will grab my setting from my dashboard.

My code is another problem. I finally got my device to connect to Losant thanks to all of the changes necessary due to JSON updates. Any code examples for changing the PWM this way?

I don’t know of any PWM specific examples. In terms of getting the value from a dashboard to the device, I’d recommend the Input Controls Block. It can directly send a device command or invoke a workflow, which can use the Device: Command Node.

I cannot find an Input Controls block on any of the workflows. I was trying to use an Application workflow as the type but that is not a block command using Application or any of the other three workflow types. I have used the Losant API block and a Device: Command block to first grab the current setpoint and then transmit the setpoint. Not sure if my logic works, but it sounds like I can grab live dashboard data this way and MQTT it to the ESP8266.

As far as pulling a range value into the device itself, could you give me a code example? Currently, I am trying to adapt the existing toggle commands you talked about in one of your deep dives. Granted, you were showing that for an embedded edge agent rather than this scenario but I at least have something. I just want to import the range via MQTT and set it as a new value for a variable named LightLevel.

@Aaron_Field,

The input control block is not a node on a workflow, but a block on a dashboard. The input control block will allow you to configure a slide range, and then you can add a button trigger which will allow you to either trigger a workflow or send a device command. You can see in this screenshot that you can add the values from the other inputs on to the payload you will either send as a device command or button trigger.

My suggestion for you would be to try and trigger a workflow, and have that workflow open in one tab with a debug node so you can see what that payload will look like coming from the control block. And then you can also send a device command to a specific device. You will be able to see this device command come through the device log on a device details page or in your application log on the application overview page.

I hope these details help. Let me know if you have any other questions or need any other clarification.

Erin

Definitely getting closer! I can get it to send a command. Losant then assumes the device is disconnected and shows disconnected with a keepalive timeout. I think this will be resolved once I have the code fixed to actually interpret the command on the ESP8266. That is the part I am struggling with now. So I have the following code:

void handleCommand(LosantCommand *command) {
  Serial.print("Command received: ");
  Serial.println(command->name);
  
  // Perform action specific to the command received.
  LightLevel = "range-0");
    
}

The error I get now is the following:

TEST:76:16: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]

76 | LightLevel = “range-0”;

  |                ^~~~~~~~~

  |                |

  |                const char*

exit status 1

invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]

How should I go about interpreting the range value? Once I get the value in the right format and can set LightLevel to it, I can handle the PWM code.

HI @Aaron_Field,

My best guess is that you have declared LightLevel as an int somewhere else in the code and you are setting it to the string “range-0”. Instead you probably want it to be something like command->payload->range-0. A device command will always be an object with “name”, “time” and “payload” attributes.

You can see the device command come through in your application log or device log. Such as this:

For questions about why your device is disconnecting I would check out this section of the documentation on device connection logs. A keep alive timeout means there was no traffic over the connection for a certain period of time. Which does make sense if you are opening the connection and then only sending this device command to your device from Losant.

Hopefully this gets your even closer to your solution,
Erin

command->payload->range-0

Trying to set LightLevel equal to the above command brings a JSON error saying there is no member named range. I’m sorry this is so troubling for me, I just do not have a lot of experience sending commands from Losant. I am definitely connecting and sending the payload to the ESP but I think I get the timeout command because the ESP is not processing the command.

I checked your device’s command history and I do see that one was sent yesterday:

[
    {
        "payload": {
            "range-0": "50"
        },
        "name": "setLightLevel",
        "time": "2022-05-18T02:00:29.608Z"
    }
]

The error you’re referring to is being thrown on your device itself? I would change the name of the value you are sending in the payload (by changing the name of the input in the Input Controls Block) to something that does not have any special characters in it, such as lightLevel. Then, I’d try accessing the property as @Erin_Thompson suggested before: command->payload->lightLevel. Start by seeing if you can just get the value to print out in the console. Bear in mind that the value is being received as a string, not as a number - an important distinction when writing low-level code like what is running on your ESP32. If you want to send it as a number, that will require another edit to your Input Controls Block to not wrap the value in quotes.

The error you’re referring to is being thrown on your device itself? I would change the name of the value you are sending in the payload (by changing the name of the input in the Input Controls Block) to something that does not have any special characters in it, such as lightLevel . Then, I’d try accessing the property as @Erin_Thompson suggested before: command->payload->lightLevel .

Yes. The error is the following:

C:\Users\Aaron\Desktop\TEST\TEST.ino: In function 'void handleCommand(LosantCommand*)':

TEST:76:21: error: 'ArduinoJson::JsonObject' {aka 'class ArduinoJson6194_F1::ObjectRef'} has no member named 'lightLevel'

  76 |   command->payload->lightLevel;
     |                     ^~~~~~~~~~

exit status 1

'ArduinoJson::JsonObject' {aka 'class ArduinoJson6194_F1::ObjectRef'} has no member named 'lightLevel'

It seems like the error has to do with processing the command. I posted the full ESP code on my github here:GitHub - aaronfield33/Garage-Lighting

Well, in your code on that line, you just have the variable name sitting there - not operating on it or declaring it or anything, hence your syntax error. Look a couple lines up where you’re printing the command name; you should be doing the same thing here for this variable value.

Also, as of last check in your Input Controls Block, you …

  • Have changed the name of the variable in the Range Slider component.
  • Have not changed the name of the variable as you are referencing it in the Payload of your “Update State” button to match what you changed the Range Slider name to. So even if you print the value to your console, it will be undefined as you’re not actually sending it to the device (you’re still sending range-0 with a value of "{{range-0}}"
  • Are still sending the value as a string, which may or may not be OK depending on how you eventually build out the rest of the command handling code on the device

Trying to set the code to LightLevel = command->payload->lightLevel results in the same error. A JSON class error where it has no idea what lightLevel means. Trying to Serial.println(command->payload->lightLevel) results in the same error.

  • I have changed the range sliders variable name to lightLevel

  • Having the “Update State” button set to be range-0: "{{range-0}}" results in a payload named range-0 with no data. Having the “Update State” button set to be range-0: "{{lightLevel}}" results in a payload named range-0 with a data point of my desired setpoint. Having the “Update State” button set to be lightLevel: "{{lightLevel}}" results in a payload named lightLevel with a data point of my desired setpoint.

  • I am still sending it as a string as far as I know. I am unsure as to how to send it as a number although I think that will likely be easier to deal with for the remainder of the PWM code.

Take a look at this example from our client library. This demonstrates how to parse a JSON object sent as a command payload and to read specific values from it. Hopefully this will point you in the right direction.