New Plugin: MCP3008 SPI DAC

master
Michael Zanetti 2021-08-12 00:15:55 +02:00
parent f966532b57
commit c7b7fdf8fa
10 changed files with 312 additions and 1 deletions

10
debian/control vendored
View File

@ -479,6 +479,15 @@ Description: nymea.io plugin for mailnotification
This package will install the nymea.io plugin for mailnotification
Package: nymea-plugin-mcp3008
Architecture: any
Depends: ${misc:Depends},
nymea-plugins-translations,
python3-pip,
Description: MCP3008 DAC integration plugin for nymea
This package will install the nymea.io plugin for using the MCP3008 DAC.
Package: nymea-plugin-mqttclient
Architecture: any
Depends: ${shlibs:Depends},
@ -1279,6 +1288,7 @@ Depends: nymea-plugin-boblight,
nymea-plugin-gpio,
nymea-plugin-i2cdevices,
nymea-plugin-mqttclient,
nymea-plugin-mcp3008,
nymea-plugin-remotessh,
nymea-plugin-serialportcommander,
nymea-plugin-systemmonitor,

View File

@ -0,0 +1,3 @@
mcp3008/integrationpluginmcp3008.json usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/mcp3008/
mcp3008/integrationpluginmcp3008.py usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/mcp3008/
mcp3008/requirements.txt usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/mcp3008/

View File

@ -71,7 +71,7 @@
"id": "d52cd791-6d92-49e4-b46b-593cb0691d46",
"name": "channel3",
"displayName": "Channel 3",
"displayNameEvent": "Channel 1 value changed",
"displayNameEvent": "Channel 3 value changed",
"type": "double",
"defaultValue": 0,
"minValue": 0,

19
mcp3008/README.md Normal file
View File

@ -0,0 +1,19 @@
# MCP3008
This plugin adds support for the MCP3008 Analog Digital Converter to nymea.
> Note: This plugin will only work on the Raspberry Pi
## Supported Things
* MCP3008
## Requirements
* The MCP3008 must be wired up properly to the SPI interface.
* The package “nymea-plugin-mcp3008” must be installed
## More
[Adafruit tutorial](https://learn.adafruit.com/raspberry-pi-analog-to-digital-converters/mcp3008)
[MCP3008 data sheet](https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf)

View File

@ -0,0 +1,140 @@
{
"name": "mcp3008",
"displayName": "MCP3008",
"id": "c45ff005-b9e9-4334-babb-4c00d6b7b714",
"vendors": [
{
"name": "microchip",
"displayName": "Microchip Technology",
"id": "6a416628-edfc-4e15-a530-eb7c7fc00ace",
"thingClasses": [
{
"id": "b22461d4-7961-492d-b2a1-f613abc8a5fb",
"name": "mcp3008",
"displayName": "MCP3008 SPI ADC",
"createMethods": ["User"],
"paramTypes": [
{
"id": "cf97ede3-429a-4a6c-8eeb-99d7afd2eb37",
"name": "clk",
"displayName": "CLK",
"type": "uint",
"defaultValue": 11
},
{
"id": "2e84602a-ef28-4f8c-bd0b-233036155da3",
"name": "miso",
"displayName": "MISO",
"type": "uint",
"defaultValue": 9
},
{
"id": "7dc0d2f1-2960-4fdc-b77b-3ab93a33fa6c",
"name": "mosi",
"displayName": "MOSI",
"type": "uint",
"defaultValue": 10
},
{
"id": "0771e974-008e-4190-bee7-efb6163decc5",
"name": "cs",
"displayName": "CS",
"type": "uint",
"defaultValue": 8
}
],
"stateTypes":[
{
"id": "1c95c1ca-8043-4096-9e0c-62d6a9bcd468",
"name": "channel1",
"displayName": "Channel 1",
"displayNameEvent": "Channel 1 value changed",
"type": "double",
"defaultValue": 0,
"minValue": 0,
"maxValue": 3.3,
"ioType": "analogInput"
},
{
"id": "cf354a91-f994-47ef-aeeb-2f03e54f1d7a",
"name": "channel2",
"displayName": "Channel 2",
"displayNameEvent": "Channel 2 value changed",
"type": "double",
"defaultValue": 0,
"minValue": 0,
"maxValue": 3.3,
"ioType": "analogInput"
},
{
"id": "b0beb2b3-cb44-488f-b0e8-a6f3433b6683",
"name": "channel3",
"displayName": "Channel 3",
"displayNameEvent": "Channel 3 value changed",
"type": "double",
"defaultValue": 0,
"minValue": 0,
"maxValue": 3.3,
"ioType": "analogInput"
},
{
"id": "c4f1cf54-427a-4b91-aa5e-7256e1b130bf",
"name": "channel4",
"displayName": "Channel 4",
"displayNameEvent": "Channel 4 value changed",
"type": "double",
"defaultValue": 0,
"minValue": 0,
"maxValue": 3.3,
"ioType": "analogInput"
},
{
"id": "593cdc76-25ec-4252-90ce-8a8da01cf328",
"name": "channel5",
"displayName": "Channel 5",
"displayNameEvent": "Channel 5 value changed",
"type": "double",
"defaultValue": 0,
"minValue": 0,
"maxValue": 3.3,
"ioType": "analogInput"
},
{
"id": "0e3a1f3d-eb4d-4bd5-bfe8-c1404713039e",
"name": "channel6",
"displayName": "Channel 6",
"displayNameEvent": "Channel 6 value changed",
"type": "double",
"defaultValue": 0,
"minValue": 0,
"maxValue": 3.3,
"ioType": "analogInput"
},
{
"id": "3d53239b-51ee-4097-8028-291ff063b3ca",
"name": "channel7",
"displayName": "Channel 7",
"displayNameEvent": "Channel 7 value changed",
"type": "double",
"defaultValue": 0,
"minValue": 0,
"maxValue": 3.3,
"ioType": "analogInput"
},
{
"id": "c10ed6ba-0248-477d-98ad-23d7318b6468",
"name": "channel8",
"displayName": "Channel 8",
"displayNameEvent": "Channel 8 value changed",
"type": "double",
"defaultValue": 0,
"minValue": 0,
"maxValue": 3.3,
"ioType": "analogInput"
}
]
}
]
}
]
}

View File

@ -0,0 +1,116 @@
import nymea
import RPi.GPIO as GPIO
pluginTimer = None
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
if ((adcnum > 7) or (adcnum < 0)):
return -1
GPIO.output(cspin, True)
GPIO.output(clockpin, False) # start clock low
GPIO.output(cspin, False) # bring CS low
commandout = adcnum
commandout |= 0x18 # start bit + single-ended bit
commandout <<= 3 # we only need to send 5 bits here
for i in range(5):
if (commandout & 0x80):
GPIO.output(mosipin, True)
else:
GPIO.output(mosipin, False)
commandout <<= 1
GPIO.output(clockpin, True)
GPIO.output(clockpin, False)
adcout = 0
# read in one empty bit, one null bit and 10 ADC bits
for i in range(12):
GPIO.output(clockpin, True)
GPIO.output(clockpin, False)
adcout <<= 1
if (GPIO.input(misopin)):
adcout |= 0x1
GPIO.output(cspin, True)
adcout >>= 1 # first bit is 'null' so drop it
return adcout
def setupThing(info):
logger.log("SetupThing for MCP3008:", info.thing.name)
SPICLK = info.thing.paramValue(mcp3008ThingClkParamTypeId)
SPIMISO = info.thing.paramValue(mcp3008ThingMisoParamTypeId)
SPIMOSI = info.thing.paramValue(mcp3008ThingMosiParamTypeId)
SPICS = info.thing.paramValue(mcp3008ThingCsParamTypeId)
try:
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) #to specify whilch pin numbering system
# set up the SPI interface pins
GPIO.setup(SPIMOSI, GPIO.OUT)
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPICLK, GPIO.OUT)
GPIO.setup(SPICS, GPIO.OUT)
logger.log("Reading channel 0")
chan0Value = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
logger.log('Raw ADC Value: %s' % chan0Value)
logger.log('ADC Voltage: %sV' % str("%.2f"%((chan0Value/1024.)*5)))
except Exception as e:
logger.warn("Unable to open SPI port", str(e))
info.finish(nymea.ThingErrorHardwareFailure, "Unable to connect to the device. Please verify it is connected properly to the SPI interface.")
return
info.finish(nymea.ThingErrorNoError)
global pluginTimer
if pluginTimer is None:
pluginTimer = nymea.PluginTimer(5, pollChannels)
def thingRemoved(thing):
del devices[thing]
if len(myThings()) == 0:
GPIO.cleanup()
def pollChannels():
for thing in myThings():
SPICLK = thing.paramValue(mcp3008ThingClkParamTypeId)
SPIMISO = thing.paramValue(mcp3008ThingMisoParamTypeId)
SPIMOSI = thing.paramValue(mcp3008ThingMosiParamTypeId)
SPICS = thing.paramValue(mcp3008ThingCsParamTypeId)
try:
chan0Value = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
thing.setStateValue(mcp3008Channel1StateTypeId, str("%.2f"%((chan0Value/1024.)*5)))
chan0Value = readadc(1, SPICLK, SPIMOSI, SPIMISO, SPICS)
thing.setStateValue(mcp3008Channel2StateTypeId, str("%.2f"%((chan0Value/1024.)*5)))
chan0Value = readadc(2, SPICLK, SPIMOSI, SPIMISO, SPICS)
thing.setStateValue(mcp3008Channel3StateTypeId, str("%.2f"%((chan0Value/1024.)*5)))
chan0Value = readadc(3, SPICLK, SPIMOSI, SPIMISO, SPICS)
thing.setStateValue(mcp3008Channel4StateTypeId, str("%.2f"%((chan0Value/1024.)*5)))
chan0Value = readadc(4, SPICLK, SPIMOSI, SPIMISO, SPICS)
thing.setStateValue(mcp3008Channel5StateTypeId, str("%.2f"%((chan0Value/1024.)*5)))
chan0Value = readadc(5, SPICLK, SPIMOSI, SPIMISO, SPICS)
thing.setStateValue(mcp3008Channel6StateTypeId, str("%.2f"%((chan0Value/1024.)*5)))
chan0Value = readadc(6, SPICLK, SPIMOSI, SPIMISO, SPICS)
thing.setStateValue(mcp3008Channel7StateTypeId, str("%.2f"%((chan0Value/1024.)*5)))
chan0Value = readadc(7, SPICLK, SPIMOSI, SPIMISO, SPICS)
thing.setStateValue(mcp3008Channel8StateTypeId, str("%.2f"%((chan0Value/1024.)*5)))
except:
logger.warn("Failed to read values from", thing.name)

6
mcp3008/mcp3008.pro Normal file
View File

@ -0,0 +1,6 @@
TEMPLATE = aux
OTHER_FILES = integrationpluginmcp3008.json \
integrationpluginmcp3008.py \
MCP3008.py

13
mcp3008/meta.json Normal file
View File

@ -0,0 +1,13 @@
{
"title": "MCP3008",
"tagline": "Connect MCP3008 digital analog converters to nymea.",
"icon": "",
"stability": "consumer",
"offline": false,
"technologies": [
"SPI"
],
"categories": [
"DYI"
]
}

3
mcp3008/requirements.txt Normal file
View File

@ -0,0 +1,3 @@
RPi.GPIO==0.7.0 \
--hash=sha256:7424bc6c205466764f30f666c18187a0824077daf20b295c42f08aea2cb87d3f \
--hash=sha256:6a4791f41cafc2ee6e4cb70e5bd31fadc66a0cfab29b38df8723a98f6f73ad5a

View File

@ -39,6 +39,7 @@ PLUGIN_DIRS = \
netatmo \
networkdetector \
nuki \
mcp3008 \
onewire \
openuv \
openweathermap \