Skip to content

AttributeError: 'NoneType' object has no attribute 'write' #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Marc1974 opened this issue May 11, 2020 · 20 comments
Closed

AttributeError: 'NoneType' object has no attribute 'write' #4

Marc1974 opened this issue May 11, 2020 · 20 comments

Comments

@Marc1974
Copy link

Hi,
I am trying to read my Smart Meter using this libraray.
I am using a USB to IR adapter and I am trying to read it via the d0 interface.
I made a fresh install on a raspberry pi 4 with raspian buster lite and I continue to get the above failure message. Do you have any ideas on how to resolve the issue ?

It would be great, if anyone coulde help.

Thank you

Marc

Actual code:
from iec62056_21.client import Iec6205621Client
client = Iec6205621Client.with_serial_transport(port='/dev/ttyUSB0')
password_challange = client.access_programming_mode()
client.send_password('00000000') # Common standard password
data_answer = client.read_value('1.8.0')
print("Result:")
print(data_answer)

Full Error message:
Traceback (most recent call last):
File "reader.py", line 5, in
password_challange = client.access_programming_mode()
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/client.py", line 164, in access_programming_mode
self.startup()
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/client.py", line 143, in startup
self.send_init_request()
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/client.py", line 239, in send_init_request
self.transport.send(request.to_bytes())
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/transports.py", line 174, in send
self._send(data)
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/transports.py", line 256, in _send
self.port.write(data)
AttributeError: 'NoneType' object has no attribute 'write'

PS: During the install I was only able to install the libraray using pip3 instead of pip.

@dawidce
Copy link

dawidce commented May 15, 2020

Hi,

same error here.
Trying to install library. It only works with pip3. Im trying to connect to meter with /dev/ttyUSB0 (usb to rs485 converter). It gives me this error :

File "iec.py", line 5, in
password_challange = client.access_programming_mode()
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/client.py", line 164, in access_programming_mode
self.startup()
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/client.py", line 143, in startup
self.send_init_request()
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/client.py", line 239, in send_init_request
self.transport.send(request.to_bytes())
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/transports.py", line 174, in send
self._send(data)
File "/home/pi/.local/lib/python3.7/site-packages/iec62056_21/transports.py", line 256, in _send
self.port.write(data)
AttributeError: 'NoneType' object has no attribute 'write'

my code:
from iec62056_21.client import Iec6205621Client

client = Iec6205621Client.with_serial_transport(port='/dev/ttyUSB0')

password_challange = client.access_programming_mode()

client.send_password('00000000') # Common standard password

data_answer = client.read_value('1.8.0')

print(data_answer)

any help ?

@Krolken
Copy link
Contributor

Krolken commented May 16, 2020

Hi

It seem like I have forgotten to add a crucial part of connection to the meter in the README.

You will need to call .connect() to actually create the connection.
I did find some other errors in the execution of accessing programming mode. This is due to the fact that we are only using this library in production for LIS-200 devices. We have not done all the necessary testing on some standard IEC62056-21 devices. I ran your snippets agains a swedish IEC62056-21 meter after adding the connect call and it seem like I need to fix some things.

But maybe you don't need the programming mode? I find that using the standard readout, that is not password protected is quite useful when fiddling with your meter at home.

What devices are you guys using? Model and manufacturer. And maybe what country you are in. Some utility companies limits the functionality over the optical port.

Could you try the following code and see if you get a response from the meter:

from iec62056_21.client import Iec6205621Client
import logging
# set up logging so you get a bit nicer printout of what is happening.
logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s,%(msecs)d %(levelname)s: %(message)s",
    datefmt="%H:%M:%S",
)

client = Iec6205621Client.with_serial_transport(port="/dev/tty.usbserial-A704H991")
client.connect()
data_answer = client.standard_readout()
print(data_answer)

I will update the example to a simpler one: #5

@Marc1974
Copy link
Author

Marc1974 commented May 17, 2020

Hi
thank you very much for your help.
I tried your code suggestion (adapting the serial port) and got the following response

18:56:26,135 INFO: Staring init sequence
18:56:26,136 INFO: Sending request message: RequestMessage(device_address='')
18:56:26,214 DEBUG: Sent b'/?!\r\n' over transport: SerialTransport
18:56:26,214 DEBUG: Resting for 0.25 seconds
Traceback (most recent call last):
File "read.py", line 12, in
data_answer = client.standard_readout()
File "/usr/local/lib/python3.7/dist-packages/iec62056_21/client.py", line 179, in standard_readout
self.startup()
File "/usr/local/lib/python3.7/dist-packages/iec62056_21/client.py", line 145, in startup
ident_msg = self.read_identification()
File "/usr/local/lib/python3.7/dist-packages/iec62056_21/client.py", line 247, in read_identification
data = self.transport.simple_read(start_char="/", end_char="\x0a")
File "/usr/local/lib/python3.7/dist-packages/iec62056_21/transports.py", line 147, in simple_read
raise TimeoutError(f"Read in {self.class.name} timed out")
TimeoutError: Read in SerialTransport timed out

I assume I do not get a response from the energy meter. The device I am trying to read is a Landis & Gyr E450 and I am living in Switzerland.

When I do try to communicate with the device in a very simple manner (b"/x2F/x3F/x21/x0D/x0A" over the serial port with 300 or 9600 baud) I also do not get a response from the device.

Is it correct to assume, that my network supplier needs to activate the d0 optical interface.

Thank you very much

Marc

@Marc1974 Marc1974 reopened this May 17, 2020
@Marc1974
Copy link
Author

Sorry - I hit the wrong button.

@Krolken
Copy link
Contributor

Krolken commented May 18, 2020

Your D0 port should be active. But it could have been set to only accept DLMS messages.
But I don't think that is the case. I remember having some issues with a L+G E350 a couple of years back, but I cant remember exactly what it was.

First thing to try is to add the address to the RequestMessage. The problem is that I seem to have forgotten to add that use case in this library. I know I have it in a previous version that I did for a client but could not open source.
It will also be needed for @dawidce use-case if he is using RS485. Over RS485 there is the possibility to have several meters on the line so an address needs to be sent so the meters know you are talking to them. I have opened up an issue about it , #9 ,and it should be include in a release soon.

To test if it is the address that is missing try the following code:

import serial
from iec62056_21.messages import RequestMessage
import logging

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s,%(msecs)d %(levelname)s: %(message)s",
    datefmt="%H:%M:%S",
)

PORT_NAME = "/dev/tty.usbserial-A704H991"
DEVICE_ADDRESS = "7820130"

port = serial.Serial(
    PORT_NAME,
    baudrate=300,
    parity=serial.PARITY_EVEN,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.SEVENBITS,
    writeTimeout=0,
    timeout=30,
    rtscts=False,
    dsrdtr=False,
    xonxoff=False,
)

request_msg = RequestMessage(device_address=DEVICE_ADDRESS)

port.write(request_msg.to_bytes())

print(port.readline())

The Device address should be printed on you meter. usually 7-8 numbers. (could be more though)

@Marc1974
Copy link
Author

Hi
I checked my device this evening. Right at the d0 port it says:

image

My energy provider also informed me, that the port is available and that the password is the initial one.

I tried the commands above and got only an empty binary string
b''

How would I proceed if the device requires a DLMS message ?

Thank you very much for your support.

@Krolken
Copy link
Contributor

Krolken commented May 19, 2020

Did you find the address of the meter and used that in the code? The empty bytes are just because you hit the timeout.

I do think you should be able to get a response somehow.

Here is where the address should be from some online pictures I found.
Screenshot 2020-05-19 at 10 02 16

I am writing a DLMS library but I am not supporting communiation via the local port yet. https://github.com/pwitab/dlms-cosem. But it is next on my todo list

You can always try Gurux, but I find it to be a bit messy.

@Marc1974
Copy link
Author

Hi,
I finally managed to get a response at all.

I tried a couple of times the code above and never got a response. Even with the right serial ID.
I started to wonder, if my reading head has the right position and I modified its position on the smart meter. After I pulled it back by 1-2mm I finally got a response.
It seem that the optical distance from my reading device and the smart meter was not matching.

With your code example above I now get b'?44337606!\r\n' as a response. The number represents the serial ID of the smart meter.

Where can I find the different value ID's to read ?

Thank you very much for your support

best regards

Marc

@Krolken
Copy link
Contributor

Krolken commented May 22, 2020

Hmm. I think you are getting optical echo from the write command if you don't have the optical probe flush against the meter. TX is bouncing to RX and you just receive the same message as you are sending.

request_msg = RequestMessage(device_address="44337606") 

would produce the bytes you are receiveing.

@Krolken
Copy link
Contributor

Krolken commented May 22, 2020

Just one question. When you where talking to your energy provider, did they refer to the port as the "Kundenschnittstelle"? That is usually a different port on the meter that is a physical connection, like RJ12.

@Marc1974
Copy link
Author

I removed the tape and the IR-head sits again straight on the smart meter.
Trying the code above with the right SerialNr. yields no response :-(

I asked my energy supplier if the optical port needs to be activated. They confirmed, that it is active , operating a 300 baud and uses for reading the standard password "0000.0000"

The last test code is not using the password anywhere. Could be the root cause ?

@Krolken
Copy link
Contributor

Krolken commented May 25, 2020

No I don't think so.

  1. Request communication with meter

Send: b'?!\r\n'
or with address
Send: b'?44337606!\r\n'

  1. The device returns its identification. You can now verify it is the correct meter and you get some extra information about how to communicate with the meter. This is the message we are looking for.
    < Receive: b'LGY@jdksjdkfn134\r\n'
  2. You send an Ack-with-option-select. Enter programming mode, switch baudrate etc.
  3. Meter sends a password request if needed.
  4. You send password.
  5. Request data from the meter.

@Marc1974
Copy link
Author

I am very thankful for your support. I tried both using the following code, no success :-(

I am wondering, if my meter is broke or if there is any other setting, on the device that I need to do.
I contacted Landys & Gyr, to see if they come up with a response. (Although chances are pretty low).

import serial
import time

ser = serial.Serial('/dev/ttyUSB0', 300, timeout=10,bytesize=7,parity=serial.PARITY_EVEN, rtscts=False,dsrdtr=False,
            xonxoff=False)

print (ser.isOpen)
time.sleep(0.1)
ser.flushInput()
ser.flushOutput()

ser.write(b'?44337606!\r\n')
time.sleep(0.5)
print("send")
ser.flush()
print("response")
resp=(ser.readline())
print (resp)
time.sleep(0.5)
ser.close()
print (ser.isOpen)

The response I got was empty

<bound method SerialBase.isOpen of Serial<id=0xb339c750, open=True>(port='/dev/ttyUSB0', baudrate=300, bytesize=7, parity='E', stopbits=1, timeout=10, xonxoff=False, rtscts=False, dsrdtr=False)>
send
response
b''
<bound method SerialBase.isOpen of Serial<id=0xb339c750, open=False>(port='/dev/ttyUSB0', baudrate=300, bytesize=7, parity='E', stopbits=1, timeout=10, xonxoff=False, rtscts=False, dsrdtr=False)>

@Krolken
Copy link
Contributor

Krolken commented May 26, 2020

Ops. I left out the leading char in requestmessage. It starts with a slash.

Try to send either:

b'/?!\r\n'

or

b'/?44337606!\r\n'

I found some old comments and I know just sending b'/?!\r\n' to a Landis E350 gives you a response so I cannot see any good reason on why yours does not.

@Marc1974
Copy link
Author

Sorry, for taking so long ....
It tried these too ... no response.

I also asked L&G if they could help me. Their response was that I am only allowed to read the meter if I have a permission from my local energy provider. I am somewhat surprised, that I need to ask someone to access my own data ?!?. (This can not be compatible to DSGVO)

From my energy provider I got so far a good feedback. They told me that the optical port should be active and provided the baud rate & password. Still this did not resolve my issue.

L&G also mentioned that the device can be read using the DLMS protocoll. Do you know a quick way to check for a response ?

Last but not least they mentioned that I could read my data using a "Smart me" device. From what I found this seems to be an additional energy meter.

Thank you so much for your help.

@Krolken
Copy link
Contributor

Krolken commented Jun 11, 2020

Well thats the usual fluff, the meter manufacturers don't want to give all information about their devices to end users.
The device belongs to the DSO and you can always request your data from them.

I don't have a quick DLMS check, sorry.

But so far you have had no response from the meter, but you did get a response back when you held the optical probe at a distance but then you only received exactly what you sent.
Could it be a hardware issue of the optical probe? Maybe the usb-converter it is inverting the bits out to the head? It would still give a valid response back when you read your own signal but the meter wouldn't be able to interpret it.

What type of optical probe are you using?

@Marc1974
Copy link
Author

I am using this probe:

https://shop.weidmann-elektronik.de/index.php?page=product&info=24

Could it be that the optical interface is deactivated by default. Since they did not activate it actively it may not be active ? of are they active by default ?

Thank's for your help.

@Krolken
Copy link
Contributor

Krolken commented Jun 14, 2020

OK. Seems like a proper one.

They can order meters in any configuration they want pretty much. So it is hard to say.
But if your DSO says you are supposed to be able to read the meter via the optical port and you can't I would argue that they send a technician to verify the meters functionality. But depends on their policy.

I saw that there were som example programs on the website of the probe. Have you tired any of them? Seems to do the same as this library but would be good to test.

@Marc1974
Copy link
Author

Marc1974 commented Jul 3, 2020

Hi,

Finally I managed to talk to a technician from my local power supplier. He informed me, that some devices need dlms while others can be read using IEC62056. The device I have needs dlms. :-(

I tried to connect to the device using the Gurux library and finally I got a response. Now I need to understand what response it is and how I get the typical 1.7, 1.8 ... values. The Gurux library seems to be far more complicated.

If you have an hints - I would appreciate them very much.

Thank you very much for your help.

Marc

@Marc1974 Marc1974 closed this as completed Jul 3, 2020
@Krolken
Copy link
Contributor

Krolken commented Jul 4, 2020

Yay. Finally :) No problem.

Yeah DLMS is a quite a bit more complex. My own implementation is not ready yet, I need to find some time/finance to complete the design of some of the basics.

Gurux works but I also think the API flow i a bit complex. The python implementation seems to have been autogenerated from another language but it does seem to work well and the Gurux guys are very knowledgeable on DLMS.

My own implementation aims for a simpler API so one doesn't have to know that much about DLMS to use it.

If it is not too much work for you you could open up an issue in https://github.com/pwitab/dlms-cosem and describe your use case and how it is handled in Gurux. It would be good to have a well defined use case for continuing the work. I have been struggling on deciding on which end to start.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants