Skip to content
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

Question: testing *without* an arduino? #20

Open
jaimet opened this issue Oct 19, 2020 · 6 comments
Open

Question: testing *without* an arduino? #20

jaimet opened this issue Oct 19, 2020 · 6 comments

Comments

@jaimet
Copy link

jaimet commented Oct 19, 2020

Hi.

I have a few DS18B20 sensors, and now that I have studied this github repo, I am reasonably certain that at least some of them are fake. I would like to test all of my sensors, but I have no arduino. Instead, I have them connected to a "Prolific Technology PL2303 USB to TTL Converter Module" (I use digitemp to get the temperature readings).

Do you know of any way that I can run your tests using my PL2303 instead of an arduino board?

Thank you!

@cpetrich
Copy link
Owner

I'm afraid all I don't know of a solution.

Porting the arduino code is almost trivial once the following routines are available: send 1wire reset pulse, read the bus level, write/read a byte, enumerate connected devices. I guess all of this can be found somewhere in the digitemp code base. Maybe this is a call for somebody to come forward who is familiar with the internal workings of the digitemp/PL2303 setup.

@jaimet
Copy link
Author

jaimet commented Oct 30, 2020

Just a quick update: I've found this.

(usb9097.py mentions "reset-pulse", "cmd_read_bit", "dat_read" and "search_roms")

I don't know whether it will help, but it looks like it might.

@jaimet
Copy link
Author

jaimet commented Nov 14, 2020

Please ignore my previous comment about https://github.com/sken10/tpow - I could not get it working at all.

I have found a better alternative however: https://github.com/mcsakoff/pydigitemp

Interestingly, pydigitemp works better for me than the original digitemp. I wanted to get some diagnostic information out of my ds18b20 thermometers (such as whether the thermometers themselves thought they were being "externally powered" or whether they thought they were being "parasite powered") but unfortunately the original author didn't want that feature added to digitemp. pydigitemp, however, includes that feature already!:

$ python readmeGetTemperature.py 
Bus: /dev/ttyUSB0
Device: DS18B20 - Programmable Resolution Digital Termometer
ROM Code: 28070007DDF20142
Power Mode: external
Connection Mode: single-drop
Alarms: high = +31 C, low = +114 C
Resolution: 12 bits
14.125

I've only just discovered pydigitemp, so I'll keep playing and I'll see if I can port counterfeit_DS18B20 over to pydigitemp/pySerial. Watch this space...

@mdstricklin
Copy link

I've only just discovered pydigitemp, so I'll keep playing and I'll see if I can port counterfeit_DS18B20 over to pydigitemp/pySerial. Watch this space...

I know I'm way late to this party, but did you have any luck doing that?

@jaimet
Copy link
Author

jaimet commented Jun 7, 2023

I know I'm way late to this party, but did you have any luck doing that?

You may be late to the party, but don't worry - we're still here! Unfortunately, I have not yet had the time to port this over to pySerial but at least I have finally found some genuine ds18b20 sensors. 🥳🎉 I hope to be able to start the port sometime this month. (You are obvs very welcome to run with it if you wish.)

@cpetrich
Copy link
Owner

thought I'd share some Python code that I used some time ago to read 1-wire devices through a UART (or USB-to-UART converters). The method is described in the Maxim/Analog application note "Using a UART to Implement a 1-Wire Bus Master" from 2002: https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html

I never managed to get consistent measurements of conversion times in Python, though.

import serial, time

def reset(ser):
    """execute reset and return True on presence pulse"""
    ser.baudrate = 9600
    ser.write([0xF0])
    ser.flush()
    ret = ord( ser.read(1) )
    time.sleep(1e-3)
    return ret != 0xF0

def write_1(ser):
    ser.baudrate = 115200
    ser.write(0xFF)

def byte_to_raw(value):
    return [0xFF if value & (1 << bit) != 0 else 0xC0 for bit in range(8)]

def bits_to_byte(bits):
    byte = 0
    for idx, v in enumerate(bits):
        if v != v:
            raise ValueError('receive error')
        byte += (1 if v>0 else 0) << idx
    return byte

def send_bytes(ser, values, n_to_read):
    ser.baudrate = 115200
    ser.reset_output_buffer()
    ser.reset_input_buffer()
    values_out = values + [0xFF] * n_to_read
    out = []
    for value in values_out:
        out += byte_to_raw(value)
    n_written = ser.write(out)
    ser.flush()
    read = list(ser.read(n_written))

    bits = [1 if r==w==0xFF else -1 if r==w==0xC0 else 0 if w==0xFF and r != w else float('nan') for r,w in zip(read, out)]
    read_bytes = [bits_to_byte(bits[idx0:idx0+8]) for idx0 in range(0, len(bits), 8)]
    return read_bytes[len(values):]

    def to_hex(ret):
        return ' '.join(f'{v:02X}' for v in ret)

    def insert(src, what, where):
        return src[:where] + what + src[where:]

if __name__ == '__main__':
    # We are assuming there is only a single 1-wire sensor attached.
    # Define the UART port here:
    port = '/dev/serial0' # Linux
    port = 'COM10' # Win

    ser = serial.Serial(port, 9600, timeout=2, write_timeout=2)

    for _ in range(1):
        # Get attached sensor ID
        if not reset(ser): break
        ret = send_bytes(ser,[0x33],8)
        print('1-Wire Device ID', to_hex(ret))
        print('w1-style 1-Wire Device ID', insert(to_hex(ret[:1]+ret[-2:-1:-1]+ret[-1:]).replace(' ',''),'-',2))

        # read status register of the only attached sensor    
        if not reset(ser): break
        ret = send_bytes(ser,[0xCC,0xBE],9)
        print('Scratchpad Register', to_hex(ret))

        # perform measurement
        print('Initiating Temperature Measurement')
        if not reset(ser): break
        ret = send_bytes(ser,[0xCC,0x44],9)
        
        # wait 1s for data conversion
        time.sleep(1)

        if not reset(ser): break
        ret = send_bytes(ser,[0xCC,0xBE],9)
        print('Scratchpad Register', to_hex(ret))

    ser.close()

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