Ethernet/IP device: able to read attributes using CPPPO, but cannot write - python

I am working to build a Python script to communicate with an EtherNet/IP device (Graco PD2K spray system). The only documentation provided by the vendor is how to configure an Allen Bradley PLC as the client to communicate with the device.
Using the following code, I can read the array of attributes at Assembly Instance 100:
from cpppo.server.enip.get_attribute import proxy_simple
via = proxy_simple('192.168.10.5')
with via:
data, = via.read( [('#4/100/3','DINT')] )
... which results in receiving back the expected array:
[0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
(39 x 32-bit integers)
When attempting to write to the attributes at Assembly instance 150, I receive True back from the controller, but the controller does not update the parameters. It is expecting 25 x 32-bit integer array:
with via:
result, = via.read([('#4/150/3=(DINT)4, 1, 0, 0, 1, 0, 0, 0, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0','#4/150/3')],1)
The output from above is:
#4/150/3=(DINT)4, 1, 0, 0, 1, 0, 0, 0, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 == True
If I add one integer to the array (or subtract, or attempt to set other than #4/150/3, I get back None, so it is clear I am close on the format and the command is getting through.
I have reached out to the vendor multiple times, and they insist it is a problem with Python (or, more specifically, they do not support Python and recommend integrating with a PLC).
I am wondering if the "Configuration" parameter at Assembly Instance 1 is the issue (see image above). I have tried multiple versions of the following code to try to write that parameter. Not fully understanding the EtherNet/IP protocol, I'm not even sure what that particular instance does -- however, that it is a parameter in an Allen-Bradley config indicates it is important in this case.
Code attempted:
result, = via.read([('#4/1/3=(USINT)0','#4/1/3')],1)
I have tried using the Molex EnIP utility, as well as something similar on SourceForge to take Python out of the equation, but results are similar. I have also tried the PyComm3 module, but I can't even get it to return Id information. I have also tried using -vvv with the CPPPO command line utils:
python -m cpppo.server.enip.get_attribute -a 192.168.10.5 '#4/150/3=(DINT)4, 1, 0, 0, 1, 0, 0, 0, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0' -vv -S
Results in (along with much more output that I don't believe is relevant):
11-09 12:11:18.119 MainThread enip.cli DETAIL issue Sending 1 (Context b'0')
11-09 12:11:18.120 MainThread enip.cli DETAIL pipeline Issuing 0/ 1; curr: 0 - last: -1 == 1 depth vs. max 0
11-09 12:11:18.124 MainThread enip.cli DETAIL __next__ Client CIP Rcvd: {
"send_data.interface": 0,
"send_data.timeout": 8,
"send_data.CPF.count": 2,
"send_data.CPF.item[0].type_id": 0,
"send_data.CPF.item[0].length": 0,
"send_data.CPF.item[1].type_id": 178,
"send_data.CPF.item[1].length": 4,
"send_data.CPF.item[1].unconnected_send.request.input": "array('B', [144, 0, 0, 0])",
"send_data.CPF.item[1].unconnected_send.request.service": 144,
"send_data.CPF.item[1].unconnected_send.request.status": 0,
"send_data.CPF.item[1].unconnected_send.request.status_ext.size": 0,
"send_data.CPF.item[1].unconnected_send.request.set_attribute_single": true
}
11-09 12:11:18.124 MainThread enip.cli DETAIL collect Receive 1 (Context b'0')
11-09 12:11:18.124 MainThread enip.cli DETAIL pipeline Completed 1/ 1; curr: 0 - last: 0 == 0 depth vs. max 0
Mon Nov 9 12:11:18 2020: 0: Single S_A_S #0x0004/150/3 == True
11-09 12:11:18.124 MainThread enip.cli DETAIL pipeline Pipelined 1/ 1; curr: 0 - last: 0 == 0 depth vs. max 0
11-09 12:11:18.125 MainThread enip.get NORMAL main 1 requests in 0.006s at pipeline depth 0; 153.919 TPS
Again, result of the request is True, but the controller does not update any of the parameters.
I'm not sure what to try next...

Related

How to construct a minimum bound box tuple for each geometry in a GeoDataFrame

I have a geopandas GeoDataFrame of lakes. I am trying to create a new column named 'MBB' with the bounding box for each lake.
I am using the bounds function from GeoPandas. However, this function exports minx, miny, maxx, and maxy in four separate columns.
# Preview the Use of the .bounds method to ensure it is exporting properly
lakes_a['geometry'].bounds
minx
miny
maxx
maxy
-69.37
44.19
-69.36
44.20
-69.33
44.19
-69.33
44.19
My desired output would look like the below and be able to be reinserted into the GeoPandasDataFrame
MBB
(-69.37, 44.19, -69.36, 44.20)
(-69.33, 44.19, -69.33, 44.19)
My gut tells me that I need to use either shapely.Geometry.Polygon or shapely.Geometry.box
The Polygon data used to create these is as follows.
Note: This is my first time working with GeoPandas (and new to Python as well); please forgive me if I made any mistakes :)
POLYGON Z ((-69.37232840276027 44.202966598054786 0, -69.37216940276056 44.202966598054786 0, -69.37181966942774 44.20276073138842 0, -69.37156540276146 44.20154879805699 0, -69.37092960276249 44.20138873139058 0, -69.370580002763 44.20111433139101 0, -69.37051640276309 44.20049693139197 0, -69.37042106942994 44.20042833139206 0, -69.37038926942995 44.20015393139249 0, -69.37013506943038 44.19976513139312 0, -69.36969020276439 44.19939919806035 0, -69.36838700276638 44.19903333139422 0, -69.36800546943368 44.198827531394556 0, -69.36787826943385 44.19864459806149 0, -69.3678466694339 44.19784419806274 0, -69.36797380276704 44.1973183313969 0, -69.36876860276584 44.19663233139795 0, -69.36759246943433 44.19658639806471 0, -69.3667658694356 44.1971809980638 0, -69.36641646943616 44.19722673139705 0, -69.36597146943683 44.19695219806414 0, -69.36549480277091 44.196403398065 0, -69.36470006943881 44.19583173139921 0, -69.36425520277282 44.19562593139955 0, -69.3618714694432 44.19500819806717 0, -69.36158546944364 44.19471099806759 0, -69.36152220277705 44.193887798068886 0, -69.36066406944508 44.19363613140263 0, -69.3604098027788 44.19345319806956 0, -69.3604098027788 44.193270198069854 0, -69.36066420277837 44.192995798070285 0, -69.36069540277833 44.19279379807057 0, -69.36069600277835 44.19278999807062 0, -69.36082306944479 44.19276719807061 0, -69.36098206944456 44.19237839807124 0, -69.3623808694424 44.19091499807348 0, -69.36288200277494 44.19074539807377 0, -69.36292126944159 44.19073213140712 0, -69.36342966944079 44.19084653140692 0, -69.36371580277364 44.191029531406684 0, -69.3639380027733 44.19198999807185 0, -69.36419220277293 44.19217279807157 0, -69.36451000277242 44.192195731404865 0, -69.36520940277131 44.191784131405484 0, -69.36587680277029 44.19157833140582 0, -69.3665442694359 44.19157853140581 0, -69.36733886943472 44.191761398072174 0, -69.36772020276743 44.19199013140519 0, -69.36791080276714 44.192516131404375 0, -69.368006002767 44.19256193140427 0, -69.36803786943364 44.19281339807054 0, -69.36845100276634 44.192767598070645 0, -69.36861000276605 44.19210453140499 0, -69.3694046027648 44.19155559807251 0, -69.36997680276392 44.1913039980729 0, -69.37058060276303 44.19118973140644 0, -69.37340926942528 44.19130413140624 0, -69.37448980275695 44.191601331405764 0, -69.37506200275607 44.19155559807251 0, -69.37541146942215 44.191326931406195 0, -69.37579286942156 44.19137273140615 0, -69.3759200027547 44.19146413140601 0, -69.37588826942141 44.19208153140505 0, -69.37534800275563 44.19322493140328 0, -69.37525260275572 44.19397959806872 0, -69.37541166942219 44.19436839806815 0, -69.37582466942155 44.19489433140069 0, -69.37633326942074 44.19521439806681 0, -69.37671466942015 44.19532873139997 0, -69.37798606941817 44.19532859806668 0, -69.37817680275123 44.19542013139983 0, -69.37801800275145 44.19578599806596 0, -69.37757286941883 44.19601473139892 0, -69.3765240027538 44.19601473139892 0, -69.37601546942125 44.19628913139849 0, -69.37557046942192 44.196723598064466 0, -69.37531620275564 44.1972039313971 0, -69.37528446942235 44.198598798061596 0, -69.37544340275548 44.19921619806064 0, -69.37582486942154 44.199970931392784 0, -69.37588846942145 44.20049679805862 0, -69.37607920275445 44.2009541980579 0, -69.37607926942115 44.20184593138987 0, -69.37582486942154 44.20223473138924 0, -69.37493486942293 44.2030807980546 0, -69.3744898694236 44.20337813138747 0, -69.37394946942442 44.20351539805392 0, -69.37340920275864 44.20351539805392 0, -69.37293226942603 44.2031037980546 0, -69.37232840276027 44.202966598054786 0))
POLYGON Z ((-69.33154920282357 44.19536753139994 0, -69.33170806948999 44.195504798066395 0, -69.3318348694898 44.19584779806587 0, -69.33212086948936 44.196076598065474 0, -69.33224780282251 44.196396798064995 0, -69.3329150028215 44.19676293139776 0, -69.33291466948816 44.19706019806398 0, -69.33278746948832 44.19726599806364 0, -69.33211986948936 44.19733433139686 0, -69.33103926949104 44.19719673139707 0, -69.3307216028249 44.19701373139736 0, -69.33069020282494 44.19653339806479 0, -69.33046780282524 44.19630473139847 0, -69.33046800282528 44.1960073980656 0, -69.33094520282452 44.195458798066454 0, -69.33154920282357 44.19536753139994 0))
You could use pandas.DataFrame.to_records:
pd.Series(
lakes_a['geometry'].bounds.to_records(index=False),
index=lakes_a.index,
)

SymPy rank different from NumPy matrix rank

Given some SymPy matrix M
M = Matrix([
[0.000111334436666596, 0.00114870370895408, -0.000328330524152990, 5.61388353859808e-6, -0.000464532588930332, -0.000969955779635878, 1.70579589853818e-5, -5.77891177019884e-6, -0.000186812539472235, -2.37115911398055e-5],
[-0.00105346453420510, 0.000165063406707273, -0.00184449574409890, 0.000658080565333929, 0.00197652092300241, 0.000516180213512589, 9.53823860082390e-5, 0.000189858427211978, -3.80494288487685e-5, 0.000188984043643408],
[-0.00102465075104153, -0.000402915220398109, 0.00123785300884241, -0.00125808154543978, 0.000126618511490838, 0.00185985865307693, 0.000123626008509804, 0.000211557638637554, 0.000407232404255796, 1.89851719447102e-5],
[0.230813497584639, -0.209574389008468, 0.742275067362657, -0.202368828927654, -0.236683258718819, 0.183258819107153, 0.180335891933511, -0.530606389541138, -0.379368598768419, 0.334800403899511],
[-0.00102465075104153, -0.000402915220398109, 0.00123785300884241, -0.00125808154543978, 0.000126618511490838, 0.00185985865307693, 0.000123626008509804, 0.000211557638637554, 0.000407232404255796, 1.89851719447102e-5],
[0.00105346453420510, -0.000165063406707273, 0.00184449574409890, -0.000658080565333929, -0.00197652092300241, -0.000516180213512589, -9.53823860082390e-5, -0.000189858427211978, 3.80494288487685e-5, -0.000188984043643408],
[0.945967255845168, -0.0468645728473480, 0.165423896937049, -0.893045423193559, -0.519428986944650, -0.0463256408085840, -0.0257001217930424, 0.0757328764368606, 0.0541336731317414, -0.0477734271777646],
[-0.0273371493900004, -0.954100482348723, -0.0879282784854250, 0.100704543595514, -0.243312734473589, -0.0217088779350294, 0.900584332231093, 0.616061129532614, 0.0651163853434486, -0.0396603397583054],
[0.0967584768347089, -0.0877680087304911, -0.667679934757176, -0.0848411039101494, -0.0224646387789634, -0.194501966574153, 0.0755161040544943, 0.699388977592066, 0.394125039254254, -0.342798611994521],
[-0.000222668873333193, -0.00229740741790816, 0.000656661048305981, -1.12277670771962e-5, 0.000929065177860663, 0.00193991155927176, -3.41159179707635e-5, 1.15578235403977e-5, 0.000373625078944470, 4.74231822796110e-5]
])
I have calculated SymPy rank() and rref() of the matrix. Rank is 7 and rref() result is:
Matrix([
[1, 0, 0, 0, 0, 0, 0, -5.14556976678473, -3.72094268951566, 3.48581267477014],
[0, 1, 0, 0, 0, 0, 0, -5.52930150663022, -4.02230308325653, 3.79193678096199],
[0, 0, 1, 0, 0, 0, 0, 2.44893308665325, 1.83777402439421, -1.87489784909824],
[0, 0, 0, 1, 0, 0, 0, -7.33732284392352, -5.25036238623229, 4.97256759287563],
[0, 0, 0, 0, 1, 0, 0, 5.48049237370489, 3.90091366576548, -3.83642187384021],
[0, 0, 0, 0, 0, 1, 0, -10.6826798792866, -7.56560803870182, 7.45974067056387],
[0, 0, 0, 0, 0, 0, 1, -3.04726210012149, -2.66388837034592, 2.48327234504403],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
Weird thing is that if I calculate rank with either NumPy or MATLAB I get value 6 and calculating rref with MATLAB I get the expected result - last 4 rows are all zero (instead of only last 3).
Does any one know where does this difference comes from and why am I unable to get correct results with SymPy? I know that rank 6 is correct because it is system of the equations where some linear dependency exist.
Looking at the eigenvalues of your matrix, the rank is indeed 6:
array([ 1.14550481e+00+0.00000000e+00j, -1.82137718e-01+6.83443168e-01j,
-1.82137718e-01-6.83443168e-01j, 2.76223053e-03+0.00000000e+00j,
-3.51138883e-04+8.61508469e-04j, -3.51138883e-04-8.61508469e-04j,
5.21160131e-17+0.00000000e+00j, -2.65160469e-16+0.00000000e+00j,
-2.67753616e-18+9.70937977e-18j, -2.67753616e-18-9.70937977e-18j])
With the sympy version I have, I get even a rank of 8, compared to the rank 6 that numpy returns.
But actually, Sympy cannot solve the eigenvalues of this matrix due to the size of the matrix (probably related to SymPy could not compute the eigenvalues of this matrix).
So one of them, Sympy, is trying to solve symbolically the equations and find the rank (based on imperfect floating point numbers), whereas the other one, numpy, uses approximations (lapack IIRC) to find the eigenvalues. By having an adequate threshold, numpy finds the proper rank, but it could have said differently with a different threshold. Sympy tried to find the rank based on an approximate system of a perfect 6 rank system and finds that it is of rank 7 or 8. It's not surprising due to the floating point difference (Sympy moves to integers to try to find the eigenvalues, for instance, instead of staying in floating point realm).

Sending buffer to HID with python

I want to send a buffer to an HID, I have trouble making the buffer, here's my code:
buffer = [0x00]*20
print(buffer)
buffer[0:10] = {0x00,0x00,0x11,0x06,0x00,0x04,0x1A,0x00,0x00,0x0b,0xb8}
print(buffer)
the output is:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 4, 6, 11, 17, 184, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
but when I use this:
buffer[0] = 0x00
buffer[1] = 0x00
buffer[2] = 0x11
buffer[3] = 0x06
buffer[4] = 0x00
buffer[5] = 0x04
buffer[6] = 0x1A
buffer[7] = 0x00
buffer[8] = 0x00
buffer[9] = 0x0b
buffer[10] = 0xb8
The output is:
[0, 0, 17, 6, 0, 4, 26, 0, 0, 11, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0]
I also should convert from decimal to hex, for example 1000 to hex.
print(hex(1000))
It gives:
0x3e8
I want to have :
03 E8
How can I have it?
First, when you wrote these lines:
buffer[0:10] = {0x00,0x00,0x11,0x06,0x00,0x04,0x1A,0x00,0x00,0x0b,0xb8}
print(buffer)
You used braces {}, so you assigned a set to the slice [0:10] of the list buffer. And you must know that:
a set is not ordered,
a set does not store duplicated values
So the assignment replaces the values with indices 0 to 9 (so the 10 first values) with the unordered 7 values 0x00,0x11,0x06,0x04,0x1A,0x0b,0xb8. That's what you observe.
Secondly, when you wrote lines like buffer[0] = 0x00, you assign directly the first element of the list to the value 0x00, so there is no surprise.
Finally, to answer your last question and print "1000" as "03 E8", I propose you this solution:
import re
print(" ".join(re.findall(r'..',(1000).to_bytes(2,'big').hex().upper())))

Passing array arguments to my own 2D function applied on Pandas groupby

I am given the following pandas dataframe
df
long lat weekday hour
dttm
2015-07-03 00:00:38 1.114318 0.709553 6 0
2015-08-04 00:19:18 0.797157 0.086720 3 0
2015-08-04 00:19:46 0.797157 0.086720 3 0
2015-08-04 13:24:02 0.786688 0.059632 3 13
2015-08-04 13:24:34 0.786688 0.059632 3 13
2015-08-04 18:46:36 0.859795 0.330385 3 18
2015-08-04 18:47:02 0.859795 0.330385 3 18
2015-08-04 19:46:41 0.755008 0.041488 3 19
2015-08-04 19:47:45 0.755008 0.041488 3 19
I also have a function that receives as input 2 arrays:
import pandas as pd
import numpy as np
def time_hist(weekday, hour):
hist_2d=np.histogram2d(weekday,hour, bins = [xrange(0,8), xrange(0,25)])
return hist_2d[0].astype(int)
I wish to apply my 2D function to each and every group of the following groupby:
df.groupby(['long', 'lat'])
I tried passing *args to .apply():
df.groupby(['long', 'lat']).apply(time_hist, [df.weekday, df.hour])
but I get an error: "The dimension of bins must be equal to the dimension of the sample x."
Of course the dimensions mismatch. The whole idea is that I don't know in advance which mini [weekday, hour] arrays to send to each and every group.
How do I do that?
Do:
import pandas as pd
import numpy as np
df = pd.read_csv('file.csv', index_col=0)
def time_hist(x):
hour = x.hour
weekday = x.weekday
hist_2d = np.histogram2d(weekday, hour, bins=[xrange(0, 8), xrange(0, 25)])
return hist_2d[0].astype(int)
print(df.groupby(['long', 'lat']).apply(time_hist))
Output:
long lat
0.755008 0.041488 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
0.786688 0.059632 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
0.797157 0.086720 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
0.859795 0.330385 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
1.114318 0.709553 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
dtype: object

count objects created in django application in past X days, for each day

I have following unsorted dict (dates are keys):
{"23-09-2014": 0, "11-10-2014": 0, "30-09-2014": 0, "26-09-2014": 0,
"03-10-2014": 0, "19-10-2014": 0, "15-10-2014": 0, "22-09-2014": 0,
"17-10-2014": 0, "29-09-2014": 0, "13-10-2014": 0, "16-10-2014": 0,
"12-10-2014": 0, "25-09-2014": 0, "14-10-2014": 0, "08-10-2014": 0,
"02-10-2014": 0, "09-10-2014": 0, "18-10-2014": 0, "24-09-2014": 0,
"28-09-2014": 0, "10-10-2014": 0, "21-10-2014": 0, "20-10-2014": 0,
"06-10-2014": 0, "04-10-2014": 0, "27-09-2014": 0, "05-10-2014": 0,
"01-10-2014": 0, "07-10-2014": 0}
I am trying to sort it from oldest to newest.
I've tried code:
mydict = OrderedDict(sorted(mydict .items(), key=lambda t: t[0], reverse=True))
to sort it, and it almost worked. It produced sorted dict, but it has ignored months:
{"01-10-2014": 0, "02-10-2014": 0, "03-10-2014": 0, "04-10-2014": 0,
"05-10-2014": 0, "06-10-2014": 0, "07-10-2014": 0, "08-10-2014": 0,
"09-10-2014": 0, "10-10-2014": 0, "11-10-2014": 0, "12-10-2014": 0,
"13-10-2014": 0, "14-10-2014": 0, "15-10-2014": 0, "16-10-2014": 0,
"17-10-2014": 0, "18-10-2014": 0, "19-10-2014": 0, "20-10-2014": 0,
"21-10-2014": 0, "22-09-2014": 0, "23-09-2014": 0, "24-09-2014": 0,
"25-09-2014": 0, "26-09-2014": 0, "27-09-2014": 0, "28-09-2014": 0,
"29-09-2014": 0, "30-09-2014": 0}
How can I fix this?
EDIT:
I need this to count objects created in django application in past X days, for each day.
event_chart = {}
date_list = [datetime.datetime.today() - datetime.timedelta(days=x) for x in range(0, 30)]
for date in date_list:
event_chart[formats.date_format(date, "SHORT_DATE_FORMAT")] = Event.objects.filter(project=project_name, created=date).count()
event_chart = OrderedDict(sorted(event_chart.items(), key=lambda t: t[0]))
return HttpResponse(json.dumps(event_chart))
You can use the datetime module to parse the strings into actual dates:
>>> from datetime import datetime
>>> sorted(mydict .items(), key=lambda t:datetime.strptime(t[0], '%d-%m-%Y'), reverse=True)
If you want to create a json response in the format: {"22-09-2014": 0, 23-09-2014": 0, "localized date": count_for_that_date} so that oldest dates will appear earlier in the output then you could make event_chart an OrderedDict:
event_chart = OrderedDict()
today = DT.date.today() # use DT.datetime.combine(date, DT.time()) if needed
for day in range(29, -1, -1): # last 30 days
date = today - DT.timedelta(days=day)
localized_date = formats.date_format(date, "SHORT_DATE_FORMAT")
day_count = Event.objects.filter(project=name, created=date).count()
event_chart[localized_date] = day_count
return HttpResponse(json.dumps(event_chart))

Categories

Resources