Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
software:waveforms:waveforms-sdk:thingspeak [2022/09/12 12:32] – changed forum.digilentinc.com to forum.digilent.com Jeffrey | software:waveforms:waveforms-sdk:thingspeak [2024/02/28 20:02] (current) – [Inventory] James Colvin | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Sending Data from WaveForms SDK to ThingSpeak.com ====== | ||
+ | {{ : | ||
+ | ~~TechArticle~~ | ||
+ | ===== Overview ===== | ||
+ | |||
+ | ThingSpeak, created by MathWorks, is an online platform for collecting, viewing, and analyzing data in the cloud. This guide runs through the steps required to send data captured by your WaveForms SDK compatible Digilent Test and Measurement Device up to ThingSpeak and ends with two optional examples. | ||
+ | |||
+ | One example uses the Pmod MIC3 to capture sound, then, from the measurements, | ||
+ | |||
+ | For a detailed description on how to run the noise level measurement example on Analog Discovery Pro in Linux mode, check this guide: [[test-and-measurement: | ||
+ | ---- | ||
+ | ===== Inventory ===== | ||
+ | <WRAP group> | ||
+ | == Hardware == | ||
+ | * A Digilent Test and Measurement device | ||
+ | * [[test-and-measurement: | ||
+ | * [[test-and-measurement: | ||
+ | * [[test-and-measurement: | ||
+ | * [[test-and-measurement: | ||
+ | * [[test-and-measurement: | ||
+ | * [[test-and-measurement: | ||
+ | * [[test-and-measurement: | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | == Software == | ||
+ | * [[software: | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | </ | ||
+ | |||
+ | **Note:** //WaveForms can be installed by following the [[software: | ||
+ | ---- | ||
+ | ===== Configuring a ThingSpeak Channel ===== | ||
+ | |||
+ | <WRAP group>< | ||
+ | Go to [[http:// | ||
+ | </ | ||
+ | {{ : | ||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | In the // | ||
+ | </ | ||
+ | {{ : | ||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | Configure the channel settings, name, and fields. The field will be the containers for your data. Configure a field for every data type, you want to store/ | ||
+ | </ | ||
+ | {{ : | ||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | Under //API Keys//, note the **Write API Key** that will be needed to push data to the server from the custom application or script. The **Read API Key** can be used to access stored data. | ||
+ | </ | ||
+ | {{ : | ||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | When uploading data to a ThingSpeak channel, it will be displayed field-by-filed on different plots. To modify these default plots, or add other data visualization methods to your channel, you can use the visualization or widget presets, you can modify the MATLAB code of the default plots, or you can write your own code to visualize the data. | ||
+ | </ | ||
+ | {{ : | ||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | To make your visualizations/ | ||
+ | </ | ||
+ | {{ : | ||
+ | </ | ||
+ | ---- | ||
+ | |||
+ | ===== Examples ===== | ||
+ | |||
+ | <WRAP group> | ||
+ | To see the usage of the ThingSpeak channels in a project, you can try the examples provided in this guide, or you can create your own examples. | ||
+ | |||
+ | --> Noise Pollution Monitoring # | ||
+ | <WRAP group> | ||
+ | |||
+ | == Hardware Setup == | ||
+ | <WRAP group>< | ||
+ | In this example, the Pmod MIC3 microphone module will be used with a Digilent Test and Measurement Device, to measure noise level. The Pmod communicates on SPI interface which will be connected to the Test and Measurement Device' | ||
+ | </ | ||
+ | {{ : | ||
+ | </ | ||
+ | |||
+ | == Software == | ||
+ | <WRAP group> | ||
+ | The complete source code can be downloaded from here: {{ : | ||
+ | |||
+ | Discussing in detail the usage of the WaveForms SDK is beyond the scope of this project. For more information about it, check [[test-and-measurement: | ||
+ | |||
+ | For a demo project with Pmod MIC3, check [[https:// | ||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | At the beginning of the script, the necessary modules are imported, then the address of the ThingSpeak channel is defined. To access your own channel, use your own API key in the address. | ||
+ | |||
+ | DIO lines used to communicate with the Pmod, as well as global variables controlling communication and data processing are also defined here. Before calling any function from the WaveForms SDK, it is necessary to load the dynamic library. | ||
+ | </ | ||
+ | """ | ||
+ | import sys # This module provides access to some objects used or maintained by the interpreter and to functions that interact strongly with the interpreter | ||
+ | import time # This module provides various functions to manipulate time values | ||
+ | from ctypes import * # C data types in Python | ||
+ | import signal | ||
+ | import requests | ||
+ | |||
+ | # ---------------------------------------------------------------------------------------------------------- | ||
+ | |||
+ | """ | ||
+ | url = " | ||
+ | |||
+ | # ---------------------------------------------------------------------------------------------------------- | ||
+ | |||
+ | """ | ||
+ | # define the communication frequency in Hz | ||
+ | spi_frequency = 1e6 | ||
+ | # pin used for chip select (DIO 24 on Digital Discovery) | ||
+ | spi_CS = 0 | ||
+ | # pin used for master in - slave out (DIO 25 on Digital Discovery) | ||
+ | spi_MISO = 1 | ||
+ | # pin used for serial clock (DIO 26 on Digital Discovery) | ||
+ | spi_SCK = 2 | ||
+ | # samples to average | ||
+ | AVERAGE = 1000 | ||
+ | |||
+ | # ---------------------------------------------------------------------------------------------------------- | ||
+ | |||
+ | """ | ||
+ | if sys.platform.startswith(" | ||
+ | dwf = cdll.LoadLibrary(" | ||
+ | |||
+ | elif sys.platform.startswith(" | ||
+ | dwf = cdll.LoadLibrary("/ | ||
+ | |||
+ | else: | ||
+ | dwf = cdll.LoadLibrary(" | ||
+ | |||
+ | |||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | For repeating tasks like resetting and closing the used instruments, | ||
+ | </ | ||
+ | """ | ||
+ | |||
+ | |||
+ | def close_device(signum=0, | ||
+ | signum = frame # dummy | ||
+ | frame = signum | ||
+ | print(" | ||
+ | dwf.FDwfDigitalSpiReset(hdwf) | ||
+ | dwf.FDwfDigitalOutReset(hdwf) | ||
+ | dwf.FDwfDigitalInReset(hdwf) | ||
+ | dwf.FDwfAnalogIOEnableSet(hdwf, | ||
+ | dwf.FDwfDeviceClose(hdwf) | ||
+ | sys.exit() | ||
+ | |||
+ | # ---------------------------------------------------------------------------------------------------------- | ||
+ | |||
+ | |||
+ | """ | ||
+ | |||
+ | |||
+ | def display_error(err_msg=" | ||
+ | if err_msg == "No error": | ||
+ | err_msg = create_string_buffer(512) | ||
+ | dwf.FDwfGetLastErrorMsg(err_msg) | ||
+ | err_msg = str(err_msg.value)[2: | ||
+ | if err_msg == "": | ||
+ | err_msg = " | ||
+ | print(" | ||
+ | return err_msg | ||
+ | |||
+ | # ---------------------------------------------------------------------------------------------------------- | ||
+ | |||
+ | |||
+ | """ | ||
+ | |||
+ | |||
+ | def spi_read(): | ||
+ | lsb = c_int() | ||
+ | msb = c_int() | ||
+ | dwf.FDwfDigitalSpiSelect(hdwf, | ||
+ | time.sleep(.001) | ||
+ | spi_command = c_int(0) | ||
+ | dwf.FDwfDigitalSpiWriteRead(hdwf, | ||
+ | spi_command), | ||
+ | dwf.FDwfDigitalSpiWriteRead(hdwf, | ||
+ | spi_command), | ||
+ | time.sleep(.001) | ||
+ | dwf.FDwfDigitalSpiSelect(hdwf, | ||
+ | return lsb.value | (msb.value << 8) | ||
+ | |||
+ | # ---------------------------------------------------------------------------------------------------------- | ||
+ | |||
+ | |||
+ | """ | ||
+ | signal.signal(signal.SIGINT, | ||
+ | |||
+ | HIGH = c_int(1) | ||
+ | LOW = c_int(0) | ||
+ | DwfDigitalOutIdleZet = c_int(3) | ||
+ | |||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | Before using a Test and Measurement Device, it needs to be connected to the host computer. To safely connect it, cases in which the device is used by other software, or is not available from some other reason, should be evited. | ||
+ | </ | ||
+ | """ | ||
+ | device_count = c_int() | ||
+ | dwf.FDwfEnum(c_int(0), | ||
+ | |||
+ | if device_count.value == 0: | ||
+ | # terminate the program if no devices are connected | ||
+ | display_error(" | ||
+ | sys.exit() | ||
+ | |||
+ | for device_index in range(device_count.value): | ||
+ | # get the name of the device | ||
+ | device_name = create_string_buffer(64) | ||
+ | dwf.FDwfEnumDeviceName(device_index, | ||
+ | |||
+ | # connecting the device | ||
+ | hdwf = c_int() | ||
+ | dwf.FDwfDeviceOpen(device_index, | ||
+ | |||
+ | # check for success | ||
+ | if hdwf.value != 0: | ||
+ | break | ||
+ | |||
+ | if hdwf.value == 0: | ||
+ | # terminate the program if the device can't be connected | ||
+ | display_error() | ||
+ | sys.exit() | ||
+ | |||
+ | # display message | ||
+ | device_name = str(device_name.value)[2: | ||
+ | print(device_name + " is connected\n" | ||
+ | |||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | To start communicating with the connected Pmod, it has to be powered. In devices which support this feature, the output voltage of the power supply should be set to 3.3V, as this is the recommended operating voltage of the Pmod. However, a supply voltage of 5V shouldn' | ||
+ | |||
+ | After the microphone is powered, the SPI interface should be initialized. After setting the communication parameters, a dummy read is performed, to start driving the serial clock. | ||
+ | </ | ||
+ | """ | ||
+ | if device_name == " | ||
+ | dwf.FDwfAnalogIOChannelNodeSet(hdwf, | ||
+ | 0), c_double(3.3)) | ||
+ | elif device_name == " | ||
+ | dwf.FDwfAnalogIOChannelNodeSet(hdwf, | ||
+ | 0), c_double(True)) | ||
+ | dwf.FDwfAnalogIOChannelNodeSet(hdwf, | ||
+ | 1), c_double(3.3)) | ||
+ | elif device_name == " | ||
+ | dwf.FDwfAnalogIOChannelNodeSet(hdwf, | ||
+ | else: | ||
+ | display_error(" | ||
+ | close_device() | ||
+ | dwf.FDwfAnalogIOEnableSet(hdwf, | ||
+ | print(" | ||
+ | time.sleep(5) | ||
+ | |||
+ | # ---------------------------------------------------------------------------------------------------------- | ||
+ | |||
+ | """ | ||
+ | dwf.FDwfDigitalSpiFrequencySet(hdwf, | ||
+ | spi_frequency)) | ||
+ | dwf.FDwfDigitalSpiClockSet(hdwf, | ||
+ | dwf.FDwfDigitalSpiDataSet(hdwf, | ||
+ | dwf.FDwfDigitalSpiIdleSet(hdwf, | ||
+ | spi_mode = c_int(1) | ||
+ | dwf.FDwfDigitalSpiModeSet(hdwf, | ||
+ | dwf.FDwfDigitalSpiOrderSet(hdwf, | ||
+ | dwf.FDwfDigitalSpiSelect(hdwf, | ||
+ | |||
+ | # dummy read to start driving the channels, clock and data | ||
+ | dwf.FDwfDigitalSpiReadOne(hdwf, | ||
+ | |||
+ | print(" | ||
+ | time.sleep(1) | ||
+ | |||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | Measurements are done continuously until Ctrl+C is pressed. The results of the measurements are averaged, then converted to dB (this conversion is just an approximation of the true noise level). | ||
+ | |||
+ | The result of the conversion is pushed to the ThingSpeak channel. If a communication error appears, or the process is interrupted, | ||
+ | </ | ||
+ | """ | ||
+ | print(" | ||
+ | |||
+ | while True: | ||
+ | try: | ||
+ | # receive initial data | ||
+ | level = 0 | ||
+ | |||
+ | # average data | ||
+ | for index in range(AVERAGE): | ||
+ | level += (spi_read() / 10) / AVERAGE | ||
+ | |||
+ | # calculate noise level | ||
+ | db = 729.0532027 - level * 0.4239354122 + \ | ||
+ | pow(level, 2) * 0.8875384813 * 1e-4 - \ | ||
+ | pow(level, 3) * 0.6195715088 * 1e-8 | ||
+ | |||
+ | # send data and check for errors | ||
+ | send_state = requests.get(url+"& | ||
+ | if send_state.status_code != 200: | ||
+ | display_error(" | ||
+ | close_device() | ||
+ | except KeyboardInterrupt: | ||
+ | break | ||
+ | |||
+ | # ---------------------------------------------------------------------------------------------------------- | ||
+ | |||
+ | """ | ||
+ | close_device() | ||
+ | |||
+ | </ | ||
+ | |||
+ | == Results == | ||
+ | <WRAP group>< | ||
+ | The indicators can be added from the channel' | ||
+ | |||
+ | The measured noise levels can be plotted against time, or displayed on a gauge widget. A histogram of the measured values can also be displayed, along with a virtual LED, to indicate dangerous noise levels. One important MATLAB function to use in data processing is [[https:// | ||
+ | </ | ||
+ | {{ : | ||
+ | {{ : | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <-- | ||
+ | |||
+ | --> Impedance Analyzer # | ||
+ | <WRAP group> | ||
+ | |||
+ | == Hardware Setup == | ||
+ | <WRAP group>< | ||
+ | In this example, the Impedance Analyzer will be used, along with an Analog Discovery board, to measure the resistance, the reactance and the capacitance of different electronic components. In this guide the [[https:// | ||
+ | </ | ||
+ | {{ : | ||
+ | </ | ||
+ | |||
+ | == Software == | ||
+ | <WRAP group> | ||
+ | The complete source code can be downloaded from here: {{ : | ||
+ | |||
+ | Discussing in detail the usage of the WaveForms SDK is beyond the scope of this project. For more information about it, check [[test-and-measurement: | ||
+ | |||
+ | For a demo project with the Impedance Analyzer, check: [[test-and-measurement: | ||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | At the beginning of the script, the necessary modules are imported, then the address of the ThingSpeak channel is defined. To access your own channel, use your own Write API key in the address. Before calling any function from the WaveForms SDK, it is necessary to load the dynamic library. | ||
+ | </ | ||
+ | """ | ||
+ | DWF Python Example | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | """ | ||
+ | |||
+ | from ctypes import * | ||
+ | from dwfconstants import * | ||
+ | import math | ||
+ | import time | ||
+ | import sys | ||
+ | import numpy | ||
+ | import requests | ||
+ | |||
+ | url = " | ||
+ | |||
+ | if sys.platform.startswith(" | ||
+ | dwf = cdll.LoadLibrary(" | ||
+ | elif sys.platform.startswith(" | ||
+ | dwf = cdll.LoadLibrary("/ | ||
+ | else: | ||
+ | dwf = cdll.LoadLibrary(" | ||
+ | |||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | Before using a Test and Measurement Device, it needs to be connected to the host computer. To safely connect it, cases in which the device is used by other software, or is not available from some other reason, should be signaled to the user. | ||
+ | </ | ||
+ | version = create_string_buffer(16) | ||
+ | dwf.FDwfGetVersion(version) | ||
+ | print(" | ||
+ | |||
+ | hdwf = c_int() | ||
+ | szerr = create_string_buffer(512) | ||
+ | print(" | ||
+ | dwf.FDwfDeviceOpen(c_int(-1), | ||
+ | |||
+ | if hdwf.value == hdwfNone.value: | ||
+ | dwf.FDwfGetLastErrorMsg(szerr) | ||
+ | print(str(szerr.value)) | ||
+ | print(" | ||
+ | quit() | ||
+ | |||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | Initializing the Impedance Analyzer instrument, with a reference resistor of 1MΩ (the reference resistor of the Impedance Analyzer board) and discarding one measurement to force starting a new one. | ||
+ | </ | ||
+ | sts = c_byte() | ||
+ | frequnecy = 1e3 | ||
+ | reference = 1e6 | ||
+ | capacitance = c_double() | ||
+ | resistance = c_double() | ||
+ | reactance = c_double() | ||
+ | |||
+ | print(" | ||
+ | dwf.FDwfAnalogImpedanceReset(hdwf) | ||
+ | # 0 = W1-C1-DUT-C2-R-GND, | ||
+ | dwf.FDwfAnalogImpedanceModeSet(hdwf, | ||
+ | dwf.FDwfAnalogImpedanceReferenceSet(hdwf, | ||
+ | reference)) | ||
+ | dwf.FDwfAnalogImpedanceFrequencySet( | ||
+ | hdwf, c_double(frequnecy)) | ||
+ | dwf.FDwfAnalogImpedanceAmplitudeSet(hdwf, | ||
+ | dwf.FDwfAnalogImpedanceConfigure(hdwf, | ||
+ | time.sleep(1) | ||
+ | |||
+ | # ignore last capture, force a new one | ||
+ | dwf.FDwfAnalogImpedanceStatus(hdwf, | ||
+ | </ | ||
+ | |||
+ | <WRAP group>< | ||
+ | Measurements are done continuously until Ctrl+C is pressed. The results of the measurements uploaded to the given ThingSpeak channel. If a communication error appears, or the process is interrupted, | ||
+ | </ | ||
+ | print(" | ||
+ | |||
+ | try: | ||
+ | for i in range(1000): | ||
+ | time.sleep(60) | ||
+ | if dwf.FDwfAnalogImpedanceStatus(hdwf, | ||
+ | dwf.FDwfGetLastErrorMsg(szerr) | ||
+ | print(str(szerr.value)) | ||
+ | quit() | ||
+ | if sts.value != 2: | ||
+ | print(" | ||
+ | continue | ||
+ | dwf.FDwfAnalogImpedanceStatusMeasure( | ||
+ | hdwf, DwfAnalogImpedanceResistance, | ||
+ | dwf.FDwfAnalogImpedanceStatusMeasure( | ||
+ | hdwf, DwfAnalogImpedanceReactance, | ||
+ | dwf.FDwfAnalogImpedanceStatusMeasure( | ||
+ | hdwf, DwfAnalogImpedanceSeriesCapactance, | ||
+ | print(str(i)+" | ||
+ | str(reactance.value/ | ||
+ | r = requests.get(url+"& | ||
+ | | ||
+ | if r.status_code != 200: | ||
+ | print(r) | ||
+ | break | ||
+ | |||
+ | except KeyboardInterrupt: | ||
+ | pass | ||
+ | |||
+ | dwf.FDwfAnalogImpedanceConfigure(hdwf, | ||
+ | dwf.FDwfDeviceClose(hdwf) | ||
+ | </ | ||
+ | |||
+ | == Results == | ||
+ | <WRAP group>< | ||
+ | The measured resistances, | ||
+ | </ | ||
+ | {{ : | ||
+ | {{ : | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <-- | ||
+ | |||
+ | </ | ||
+ | ---- | ||
+ | |||
+ | ===== Next Steps ===== | ||
+ | |||
+ | Now that data can be transferred between the test and measurement device and ThingSpeak, the script can be modified as needed for your project. | ||
+ | |||
+ | For more information on WaveForms SDK, see its [[software: | ||
+ | |||
+ | For technical support, please visit the [[https:// |