Control-C program via rshell etc

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
rpr
Posts: 59
Joined: Sat Oct 27, 2018 5:17 pm

Control-C program via rshell etc

Post by rpr » Sun Aug 18, 2019 1:53 am

I have an infinite loop running on my ESP8266 started at the end of my main.py. The program works fine and is sending data over mqtt. How can I interrupt it via rshell etc? rshell keeps waiting at the "Testing if ubinascii.unhexlify exists ..." How can I send a ctrl-C? Thanks for your help.

This is my boot.py.

Code: Select all

# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
import uos, machine
#uos.dupterm(None, 1) # disable REPL on UART(0)
import gc
#import webrepl
#webrepl.start()
gc.collect()

User avatar
pythoncoder
Posts: 3543
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Control-C program via rshell etc

Post by pythoncoder » Sun Aug 18, 2019 8:06 am

I have encountered this one too. I don't know an entirely satisfactory fix. The nuclear solution is of course to erase flash and start again. The more practical way is to have main.py look like this

Code: Select all

import time
time.sleep(5)
import my_module
You should find that after a reset or power cycle you have 5 secs to connect and interrupt the program.
Peter Hinch

User avatar
Roberthh
Posts: 1572
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Control-C program via rshell etc

Post by Roberthh » Sun Aug 18, 2019 9:07 am

You could also start a different terminal emulator like Putty or picocom and push Ctrl-C there.

rpr
Posts: 59
Joined: Sat Oct 27, 2018 5:17 pm

Re: Control-C program via rshell etc

Post by rpr » Sun Aug 18, 2019 9:12 am

Peter, many thanks.

I've been using the nuclear option so far. A little annoying but worked. I will try out your more practical solution.

Online
User avatar
jimmo
Posts: 546
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia

Re: Control-C program via rshell etc

Post by jimmo » Sun Aug 18, 2019 12:26 pm

rpr wrote:
Sun Aug 18, 2019 1:53 am
I have an infinite loop running on my ESP8266
Is this just a "while True: pass". What you're describing _should_ work, so sounds like there's a bug somewhere. Do you still have the console connected to the serial port when you run rshell?
pythoncoder wrote:
Sun Aug 18, 2019 8:06 am
The more practical way is to have main.py look like this
The first thing rshell does is sent Ctrl-C twice, so I don't understand why this would be any different to the time.sleep(). Or am I missing something?

I just tested this quickly on my esp8266. I'm using `pyboard.py -f`, but it's effectively the same as rshell. (I think rshell uses pyboard.py, or a derivative of, internally).

main_loop.py:

Code: Select all

while True:
  pass

Code: Select all

pyboard.py --device /dev/ttyUSB0 -f cp main_loop.py :main.py
(soft reset ESP8266, verify in terminal that it's stuck in the infinite loop)

Code: Select all

$ ./tools/pyboard.py --device /dev/ttyUSB0 -f ls
ls :
         230 boot.py
           19 main.py

User avatar
pythoncoder
Posts: 3543
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Control-C program via rshell etc

Post by pythoncoder » Mon Aug 19, 2019 10:01 am

In the case of

Code: Select all

while True:
    pass
(to my surprise) you can indeed get in with rshell.

I have encountered cases with real applications where you cannot, and a brief delay provides a handy fix. Perhaps there are worse cases, for example if the application is waiting on a blocking call? Although in my code I try to avoid this...
Peter Hinch

User avatar
Roberthh
Posts: 1572
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Control-C program via rshell etc

Post by Roberthh » Mon Aug 19, 2019 10:14 am

That's what I tested. The problem arises when the code is waiting in a blocking call. Then ir will not be tested, whether a Ctrl-C happened.

rpr
Posts: 59
Joined: Sat Oct 27, 2018 5:17 pm

Re: Control-C program via rshell etc

Post by rpr » Mon Aug 19, 2019 10:17 pm

I'm taking sensor data from a dht22 and using Peter's mqtt_as module. Here is the code. It has been working perfectly for about 36 hours now. I'm going to let it run for a few more days to check. Though it would be nice to do a Ctrl-C.

Code: Select all

from mqtt_as import MQTTClient
from configmqtt import config
import uasyncio as asyncio
import dht
from machine import Pin

def dhtmeas():
    d = dht.DHT22(Pin(14))
    d.measure()
    return d.temperature(), d.humidity()

SERVER = '192.168.1.2'  # Change to suit e.g. 'iot.eclipse.org'

async def main(client):
    await client.connect()
    n = 0
    while True:
        await asyncio.sleep(30)
        print('publish', n)
        t, h = dhtmeas()
        print(t,h)
        msg="Temp = " + str(t) + " C ; RH = " + str(h) + " %"
        # If WiFi is down the following will pause for the duration.
        await client.publish('sensors/DHT22-01', msg, qos = 1)
        n += 1

config['server'] = SERVER

MQTTClient.DEBUG = True  # Optional: print diagnostic messages
client = MQTTClient(config)
loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main(client))
finally:
    client.close()  # Prevent LmacRxBlk:1 errors

User avatar
pythoncoder
Posts: 3543
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Control-C program via rshell etc

Post by pythoncoder » Tue Aug 20, 2019 6:38 am

I don't have an answer as to why my library prevents ctrl-c. It clearly doesn't block - it uses uasyncio and makes extensive use of concurrent tasks. The whole thing would croak if a task executed a blocking call. This has piqued my curiosity and I will investigate. Alas I'm busy at the moment so it may be a while before I get to look at it.

A workround if you need to shut it down remotely might be to subscribe to a "kill" topic and send it a message.
Peter Hinch

User avatar
pythoncoder
Posts: 3543
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Control-C program via rshell etc

Post by pythoncoder » Tue Aug 20, 2019 6:45 am

One comment on the code. This won't fix the problem but relates to general efficiency. You instantiate the DHT (and the Pin) every time you read it. My approach would be to instantiate these once only:

Code: Select all

def dhtmeas(d):
    d.measure()
    return d.temperature(), d.humidity()

SERVER = '192.168.1.2'  # Change to suit e.g. 'iot.eclipse.org'

async def main(client):
    await client.connect()
    d = dht.DHT22(Pin(14))  # Instantiate
    n = 0
    while True:
        await asyncio.sleep(30)
        print('publish', n)
        t, h = dhtmeas(d)
You might also dispense with dhtmeas and inline its contents.
Peter Hinch

Post Reply