I have a BME280 environment sensor that returns a tuple in a variable called envi.
envi = bme.values
print(envi)
returns all three values of temp, pressure and humidity.
If I print(envi[1]) I get a string returned for pressure such as '1029.23hPa'
As this returned value needs calibrating ever so slightly, I simply need to add 3 to it, before publishing it via MQTT to Adafruit via...
c.publish(conf['user']+"/feeds/pres", env[1])
What would be the correct syntax to add 3 to env[1] please?
Is there a way I can do this?
Do you want to do this ?
# Python 3.6+
envi[1] = f"{float(envi[1].strip('hPa')) + 3:.2f}hPa"
# Python pre 3.6
envi[1] = "{:.2f}hPa".format(float(envi[1].strip('hPa')) + 3)
You can use:
s = '1029.23hPa'
f'{float(s[:-3]) + 3}hPa'
# 1032.23hPa
or
f"{float(s.rstrip('hPa')) + 3}hPa"
Related
I'm using a raspberry to send some sensor data over to a SOAP webservice. RPi gets the data from the serial port. The format is 'DATE, VALUE1, VALUE2, VALUE3, VALUE4\r\n'. The webservice request looks like this
<sensors>
<Sensor>
<SensorId>int</SensorId>
<NodeId>int</NodeId>
<SensorTypeId>int</SensorTypeId>
<Value>double</Value>
<Status>string</Status>
<Date>dateTime</Date>
<Deleted>boolean</Deleted>
<Updated>boolean</Updated>
<RemoteId>int</RemoteId>
<DateOfLastUpdate>dateTime</DateOfLastUpdate>
<UserId>int</UserId>
<ErrorMessage>string</ErrorMessage>
</Sensor>
<Sensor>
<SensorId>int</SensorId>
<NodeId>int</NodeId>
<SensorTypeId>int</SensorTypeId>
<Value>double</Value>
<Status>string</Status>
<Date>dateTime</Date>
<Deleted>boolean</Deleted>
<Updated>boolean</Updated>
<RemoteId>int</RemoteId>
<DateOfLastUpdate>dateTime</DateOfLastUpdate>
<UserId>int</UserId>
<ErrorMessage>string</ErrorMessage>
</Sensor>
</sensors>
<username>string</username>
<password>string</password>
<UniqueClientID>string</UniqueClientID>
<project>string</project>
Each line I get from the serial port has 4 sensor values and the datetime these values were logged. So I need to create 4 objects with the SUDS library method client.factory.create() for each line I parse from the serial, add the values to each attribute and append() the objects to the Array of Sensor objects that the webservice accepts as its first parameter. The problem is I can't find a way to dynamically create the objects, enter the attributes' values, and append them to the big array. I'm going to parse probably 600lines from the serial port, so 4x600=2400 will need to be created. Hard-coding object names like this
while True:
serial_str = port.readline()
if serial_str:
string_list = serial_str.split(',')
date = 'T'.join( [ string_list[i] for i in [0, 1] ] )
temperature = string_list[2]
humidity = string_list[3]
rain = string_list[4]
wind = string_list[5].replace("\r\n","")
Sensor_obj1 = client.factory.create('Sensor')
Sensor_obj1.SensorId = -1
Sensor_obj1.NodeId = 1
Sensor_obj1.SensorTypeId = 2
Sensor_obj1.Value = temperature
Sensor_obj1.Status = ''
Sensor_obj1.Date = date
Sensor_obj1.Deleted = 0
Sensor_obj1.Updated = 0
Sensor_obj1.RemoteId = 0
Sensor_obj1.DateOfLastUpdate = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')datetime.now()
Sensor_obj1.UserId = 0
Sensor_obj1.ErrorMessage = ''
Sensor_list_obj.Sensor.append(Sensor_obj1)
Sensor_obj2 = client.factory.create('Sensor')
...
would work if I only had 1 line to send, but even then its a bad programming style. I just got started with python 2.x, so I would appreciate if someone would point me to the right direction here. Thanks in advance
I am not very familiar with the problem at hand, but I would guess that you can add more parameters to the call to client.factory.create('Sensor') call. Does it accept, **kwargs, so that you can call:
client.factory.create('Sensor', SensorID=-1, NodeId=1, ...)
If not, you can always abstract the initialization by:
Creating a function that does all the asignments and hides away the 'gory' details. This is elegant enough, and probably you shouldn't try anything more advanced if you have just started programming in python.
Create a class Sensor, that inherits from the one of suds. Unfortunately, I don't know enough about the class of objects 'client.factory.create'.
Also, I think I would create a list of sensors (or dictionary, if that makes sense in your code), so that you append all the sensors to that structure, otherwise your program will be impossible to use if you have three or five sensors instead of 4.
I'm using a matlab-function in simulink to call a python script, that do some calculations from the input values. The python-script gives me a string back to the matlab-function, that I split to an array. The splitted string has always to be a cell array with 6 variable strings:
dataStringArray = '[[-5.01 0.09785429][-8.01 0.01284927]...' '10.0' '20.0' '80.0' '80.0' '50.0'
To call the functions like strsplit or the python-script itself with a specific m-file, I'm using coder.extrinsic('*') method.
Now I want to index to a specific value for example with dataStringArray(3) to get '20.0' and define it as an output value of the matlab-function, but this doesn't work! I tried to predefine the dataStringArray with dataStringArray = cell(1,6); but get always the same 4 errors:
Subscripting into an mxArray is not supported.
Function 'MATLAB Function' (#23.1671.1689), line 42, column 24:
"dataStringArray(3)"
2x Errors occurred during parsing of MATLAB function 'MATLAB Function'
Error in port widths or dimensions. Output port 1 of 's_function_Matlab/MATLAB Function/constIn5' is a one dimensional vector with 1 elements.
What do I'm wrong?
SAMPLE CODE
The commented code behind the output definitions is what I need.:
function [dataArrayOutput, constOut1, constOut2, constOut3, constOut4, constOut5] = fcn(dataArrayInput, constIn1, constIn2, constIn3, constIn4, constIn5)
coder.extrinsic('strsplit');
% Python-Script String Output
pythonScriptOutputString = '[[-5.01 0.088068861]; [-4.96 0.0]]|10.0|20.0|80.0|80.0|50.0';
dataStringArray = strsplit(pythonScriptOutputString, '|');
% Outputs
dataArrayOutput = dataArrayInput; % str2num(char((dataStringArray(1))));
constOut1 = constIn1; % str2double(dataStringArray(2));
constOut2 = constIn2; % str2double(dataStringArray(3));
constOut3 = constIn3; % str2double(dataStringArray(4));
constOut4 = constIn4; % str2double(dataStringArray(5));
constOut5 = constIn5; % str2double(dataStringArray(6));
SOLUTION 1
Cell arrays are not supported in Matlab function blocks, only the native Simulink datatypes are possible.
A workaround is to define the whole code as normal function and execute it from the MATLAB-Function defined with extrinsic. It`s important to initialize the output variables with a known type and size before executing the extrinsic function.
SOLUTION 2
Another solution is to use the strfind function, that gives you a double matrix with the position of the splitter char. With that, you can give just the range of the char positions back that you need. In this case, your whole code will be in the MATLAB-Function block.
function [dataArrayOutput, constOut1, constOut2, constOut3, constOut4, constOut5] = fcn(dataArrayInput, constIn1, constIn2, constIn3, constIn4, constIn5)
coder.extrinsic('strsplit', 'str2num');
% Python-Script String Output
pythonScriptOutputString = '[[-5.01 0.088068861]; [-4.96 0.0]; [-1.01 7.088068861]]|10.0|20.0|80.0|80.0|50.0';
dataStringArray = strfind(pythonScriptOutputString,'|');
% preallocate
dataArrayOutput = zeros(3, 2);
constOut1 = 0;
constOut2 = 0;
constOut3 = 0;
constOut4 = 0;
constOut5 = 0;
% Outputs
dataArrayOutput = str2num(pythonScriptOutputString(1:dataStringArray(1)-1));
constOut1 = str2num(pythonScriptOutputString(dataStringArray(1)+1:dataStringArray(2)-1));
constOut2 = str2num(pythonScriptOutputString(dataStringArray(2)+1:dataStringArray(3)-1));
constOut3 = str2num(pythonScriptOutputString(dataStringArray(3)+1:dataStringArray(4)-1));
constOut4 = str2num(pythonScriptOutputString(dataStringArray(4)+1:dataStringArray(5)-1));
constOut5 = str2num(pythonScriptOutputString(dataStringArray(5)+1:end));
When using an extrinsic function, the data type returned is of mxArray, which you cannot index into as the error message suggests. To work around this problem, you first need to initialise the variable(s) of interest to cast them to the right data type (e.g. double). See Working with mxArrays in the documentation for examples of how to do that.
The second part of the error message is a dimension. Without seeing the code of the function, the Simulink model and how the inputs/outputs of the function are defined, it's difficult to tell what's going on, but you need to make sure you have the correct size and data type defined in the Ports and Data manager.
Hey so I am just working on some coding homework for my Python class using JES. Our assignment is to take a sound, add some white noise to the background and to add an echo as well. There is a bit more exacts but I believe I am fine with that. There are four different functions that we are making: a main, an echo equation based on a user defined length of time and amount of echos, a white noise generation function, and a function to merge the noises.
Here is what I have so far, haven't started the merging or the main yet.
#put the following line at the top of your file. This will let
#you access the random module functions
import random
#White noise Generation functiton, requires a sound to match sound length
def whiteNoiseGenerator(baseSound) :
noise = makeEmptySound(getLength(baseSound))
index = 0
for index in range(0, getLength(baseSound)) :
sample = random.randint(-500, 500)
setSampleValueAt(noise, index, sample)
return noise
def multipleEchoesGenerator(sound, delay, number) :
endSound = getLength(sound)
newEndSound = endSound +(delay * number)
len = 1 + int(newEndSound/getSamplingRate(sound))
newSound = makeEmptySound(len)
echoAmplitude = 1.0
for echoCount in range (1, number) :
echoAmplitude = echoAmplitude * 0.60
for posns1 in range (0, endSound):
posns2 = posns1 + (delay * echoCount)
values1 = getSampleValueAt(sound, posns1) * echoAmplitude
values2 = getSampleValueAt(newSound, posns2)
setSampleValueAt (newSound, posns2, values1 + values2)
return newSound
I receive this error whenever I try to load it in.
The error was:
Inappropriate argument value (of correct type).
An error occurred attempting to pass an argument to a function.
Please check line 38 of C:\Users\insanity180\Desktop\Work\Winter Sophomore\CS 140\homework3\homework_3.py
That line of code is:
setSampleValueAt (newSound, posns2, values1 + values2)
Anyone have an idea what might be happening here? Any assistance would be great since I am hoping to give myself plenty of time to finish coding this assignment. I have gotten a similar error before and it was usually a syntax error however I don't see any such errors here.
The sound is made before I run this program and I defined delay and number as values 1 and 3 respectively.
Check the arguments to setSampleValueAt; your sample value must be out of bounds (should be within -32768 - 32767). You need to do some kind of output clamping for your algorithm.
Another possibility (which indeed was the error, according to further input) is that your echo will be out of the range of the sample - that is, if your sample was 5 seconds long, and echo was 0.5 seconds long; or the posns1 + delay is beyond the length of the sample; the length of the new sound is not calculated correctly.
I found the following example from another question:
Here
It has some pyparsing code like this:
from pyparsing import *
survey = '''GPS,PN1,LA52.125133215643,LN21.031048525561,EL116.898812'''
number = Word(nums+'.').setParseAction(lambda t: float(t[0]))
separator = Suppress(',')
latitude = Suppress('LA') + number
longitude = Suppress('LN') + number
elevation = Suppress('EL') + number
line = (Suppress('GPS,PN1,')
+ latitude
+ separator
+ longitude
+ separator
+ elevation)
print line.parseString(survey)
It says that the output is:
[52.125133215643, 21.031048525561, 116.898812]
However, I get the following output:
[W:(0123...), W:(0123...), W:(0123...)]
How can I get float outputs instead of these "W:(0123...)" values?
Thanks!
I upgraded my python and pyparsing version and it still did not work correctly. However, the next morning it suddenly worked just fine. I'm not sure why, maybe the restart overnight did something. Either way, it appears to work correctly now.
I'm having some problems making Python talk to a hardware display using pyserial.
Some of the display's functions require a signed word to be sent as arguments after commands (ie. X or Y on display screen).
I've been getting by with chr() previously, but that only works with numbers < 255.
I've tried the following for conversion but it's giving some weird results, placing things way off the set position:
def ByteIt(self,data):
datastring = str()
for each in tuple(str(data)):
datastring = datastring + chr(int(each))
return datastring
I may be way off myself here :)
Example of how i would use it:
x = 100
y = 350
serial.Write('\x01' + ByteIt(x) + ByteIt(y)) # command , xpos , ypos
The thing is, when i do this, the stuff is not placed at x100,y350, most times the display will crash :(
Any tips on how this can be done properly?
Read about the struct module.
http://docs.python.org/library/struct.html
Replace all of the "chr" and stuff with proper struct.pack() calls.
Specifically
bytes = struct.pack( 'h', some_data )
Should give you a "signed word".
You may want to revise again the documentation about "pack" and "unpack". Selecting the appropriate upper-case or lower-case allows you to specify the Endianness. So, based on the example above which didn't work perfectly on your device, I presume you need:
x = 100
y = 350
serial.Write('\x01' +
struct.pack('>hh', x) +
struct.pack('>hh', y)) # command , xpos , ypos