The terminal I use on Windows is Mingw-w64 (Git Bash). I am trying to find or create a CLI menu with Python that I can navigate with arrow keys, however nothing I find works.
The Python library, simple-term-menu, doesn't work on Windows. console-menu doesn't use arrow keys but it just throws an error when I import it anyway. After importing windows-curses, I was able to get it working in CMD but not Git Bash (it says, "Redirection is not supported.")
I know for a fact that what I'm after is possible. The JavaScript framework, Adonis, is capable of it with their create command (yarn create adonis-ts-app hello-world). The NPM one doesn't work but Yarn does. Given this, it's obviously possible, but how?
Given all of this, how can I get the CLI menu I want in Git Bash, or how can I get windows-curses to work?
In Windows OS (and only for 32 bits Python versions), you can use 'unicurses' module. You can download it from pypi.org (https://pypi.org/project/UniCurses/1.2/) and install it as a .exe file.
when you have already installed it, it will appear an 'import module error', all about it is explained on this post here in SOF just in case: UniCurses pdcurses.dll Error
Basically you have to download 'pdcurses.dll' (here is a link: https://www.opendll.com/index.php?file-download=pdcurses.dll&arch=32bit&version=3.4.0.0) and move it to a specific directory. It's detalled on the post above.
Here is an example code of how this module works to use it with Arrow Keys:
from unicurses import *
WIDTH = 30
HEIGHT = 10
startx = 0
starty = 0
choices = ["Choice 1", "Choice 2", "Choice 3", "Choice 4", "Exit"]
n_choices = len(choices)
highlight = 1
choice = 0
c = 0
def print_menu(menu_win, highlight):
x = 2
y = 2
box(menu_win, 0, 0)
for i in range(0, n_choices):
if (highlight == i + 1):
wattron(menu_win, A_REVERSE)
mvwaddstr(menu_win, y, x, choices[i])
wattroff(menu_win, A_REVERSE)
else:
mvwaddstr(menu_win, y, x, choices[i])
y += 1
wrefresh(menu_win)
stdscr = initscr()
clear()
noecho()
cbreak()
curs_set(0)
startx = int((80 - WIDTH) / 2)
starty = int((24 - HEIGHT) / 2)
menu_win = newwin(HEIGHT, WIDTH, starty, startx)
keypad(menu_win, True)
mvaddstr(0, 0, "Use arrow keys to go up and down, press ENTER to select a choice")
refresh()
print_menu(menu_win, highlight)
while True:
c = wgetch(menu_win)
if c == KEY_UP:
if highlight == 1:
highlight == n_choices
else:
highlight -= 1
elif c == KEY_DOWN:
if highlight == n_choices:
highlight = 1
else:
highlight += 1
elif c == 10: # ENTER is pressed
choice = highlight
mvaddstr(23, 0, str.format("You chose choice {0} with choice string {1}", choice, choices[choice-1]))
clrtoeol()
refresh()
else:
mvaddstr(22, 0, str.format("Character pressed is = {0}", c))
clrtoeol()
refresh()
print_menu(menu_win, highlight)
if choice == 5:
break
refresh()
endwin()
And here is an image of the result on the command line interface (CMD):
The cutie library might be what you want. Example:
options = [f'Choice {i}' for i in range(1, 5)]
chosen_idx = cutie.select(options)
chosen = options[chosen_idx]
You can use InquirerPy to create a menu like this that works using keyboard navigation
#! /usr/bin/env python3
from InquirerPy import inquirer
fav_lang = inquirer.select(
message = "What's your favorite language:",
choices = ["Go", "Kotlin", "Python", "Rust", "Java", "JavaScript"]
).execute()
Related
I am running a python script on RaspberryPi 4, and today when I ran the script again, it showed me the error ModuleNotFoundError: No module named 'adafruit_ssd1306' although I ran this same script yesterday about 10 times, it ran perfectly without any errors. I did not change anything in the script, not even its location. I tried force reinstalling the library,
running the script from another location, rebooting the pi, running it as sudo but none of them worked either.
By using pip3 freeze it shows that the package is installed and trying to install the package again says that the requirement is already satisfied.
Python version: 3.7
Main.py
import time
import board
import digitalio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306
import requests
WIDTH = 128
HEIGHT = 64 # Change to 64 if needed
BORDER = 5
BASE_URL = "https://api.openweathermap.org/data/2.5/weather?"
API_KEY = "API Key"
sign = '°'
# Use for I2C.
i2c = board.I2C()
oled = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=0x3C)
dir_pin = digitalio.DigitalInOut(board.D23)
step_pin = digitalio.DigitalInOut(board.D24)
call_b = digitalio.DigitalInOut(board.D18)
dir_pin.direction = digitalio.Direction.INPUT
step_pin.direction = digitalio.Direction.INPUT
call_b.direction = digitalio.Direction.INPUT
dir_pin.pull = digitalio.Pull.UP
step_pin.pull = digitalio.Pull.UP
prev_value = True
cities = ['Delhi','Tokyo','London','San Francisco',
'kanpur','Mumbai','portugal','Toronto','Sydney','Paris','New York','Dubai',
'Moscow','Rome','Madrid','Riyadh','Bangkok','Cairo','Istanbul','Kolkata',
'Beijing','Seoul','Shanghai','Osaka','Hong Kong','Bangalore','Kathmandu',
'Chennai','Kathmandu','Manila','Jakarta','Tehran','Baghdad','Riyadh','Abu Dhabi',
'Dubai','Kuala Lumpur','Chennai','Kathmandu','Manila','Jakarta','Tehran','Baghdad']
font_size = 12
font = ImageFont.truetype('/home/pi/Desktop/Poppins-Regular.ttf', font_size)
font_big = ImageFont.truetype('/home/pi/Desktop/Poppins-Regular.ttf', font_size+4)
font_xl = ImageFont.truetype('/home/pi/Desktop/Poppins-Regular.ttf', font_size+7)
max_cities = len(cities) - 1
value = 0
def get_temp(city):
url = BASE_URL + "q=" + city + "&appid=" + API_KEY
r = requests.get(url)
if r.status_code == 200:
data = r.json()
temp = data['main']['temp']
humidity = data['main']['humidity']
temp = int(temp)
humidity = int(humidity)
temp = temp - 273
#humidity = humidity+"%"
temp = str(temp)+sign+'c'
# h = "Humidity: "+str(humidity)
return temp
def create_image(temp,city):
image = Image.new("1", (oled.width, oled.height))
draw = ImageDraw.Draw(image)
(fw,fh) = font.getsize(city)
(w,h) = font_xl.getsize(temp)
draw.text((128//2 - fw//2,12),city,fill=255,font=font) # city name
draw.text((128//2 - w//2,30),temp,fill=255,font=font_xl) # temp
return image
def text_image(city):
image_ = Image.new("1", (oled.width, oled.height))
draw = ImageDraw.Draw(image_)
(font_width, font_height) = font_big.getsize(city)
draw.text((128//2 - font_width//2, 64//2 - font_height//2),city, font=font_big, fill=255)
oled.fill(0)
oled.image(image_)
oled.show()
g = "Temprature\n Meter"
intro = Image.new("1", (oled.width, oled.height))
d = ImageDraw.Draw(intro)
# Draw text
(font_width, font_height) = font.getsize(g)
d.text((20, 6),
g, font=font_big, fill=255)
oled.fill(0)
oled.image(intro)
oled.show()
timer = 0
while True:
if prev_value != step_pin.value:
if step_pin.value == False:
if dir_pin.value == False:
print("left") # left
value = value + 1
if value > max_cities:
value = 1
print(value)
selected_city = cities[value]
print(selected_city)
text_image(selected_city)
else:
print("right") # right
if value == 0:
value = max_cities
else:
value = value - 1
print(value)
selected_city = cities[value]
print(selected_city)
text_image(selected_city)
prev_value = step_pin.value
while call_b.value == False:
timer = timer+1
if timer > 70000 and timer < 150000:
oled.fill(0)
oled.show()
timer = 0
print("blank")
time.sleep(2)
print("active")
elif timer < 15000 and timer > 500:
t = get_temp(selected_city)
print(t)
# display the data to the OLED
image = create_image(t,selected_city)
oled.fill(0) #clear display
oled.show()
oled.image(image)
oled.show()
timer = 0
time.sleep(1)
else:
timer = 0
it is sometimes happen when I forgot to activate the virtualenv, even I can install new libraries using pip or pip3 without virtualenv. But python main.py won't run. Then I realized that I haven't turn on the virtual environment.
1- make sure you typed the name of module correctly
2- make sure you use the correct python version
python3:
python3 script.py
3- also make sure it installed with the correct pip installer you may used pip for python2 by mistake
python3 -m pip install some_module
4- better way to make a virtual environment
virtualenv -p python3 env
# then
. env/bin/activate
python # ← will run python3
you may read
this answer on stack overflow about venv and pip versions
and official documentation for venv
you may search for virtual environment on raspberry pi if there is any different setups may be needed but as I remember it is most likely like Ubuntu
I program an app witgh QT interface to read modbus data, I display data on GUI create with PyQT5.
When I launch program, it crash after few second, I haven't message error. I used debugger and nothing wrong thing, program just close.
This is a part of my code where is my problem, I'll explain after
def displayModbus(self):
modbusReturn = modbus.readModbus()
commStatus = modbusReturn[0]
if commStatus:
listRegValue = modbusReturn[1]
#Display data to ui
if str(listRegValue[1]) == "1": #HEATING_ST
self.ui.lnHeatingStatus.setText("On")
else:
self.ui.lnHeatingStatus.setText("Off")
# self.ui..setText(str(listRegValue[2])) #WAIT_TIME_CHG
# self.ui..setText(str(listRegValue[3])) #RUN_TIME_CHG
if str(listRegValue[4]) == "1": #ON_WAIT_TIME_P
self.ui.ledWaitTime.setStyleSheet("QPushButton {background-color:green;}")
else:
self.ui.ledWaitTime.setStyleSheet("QPushButton {background-color:red;}")
if str(listRegValue[5]) == "1": #RUN_CYCLE
self.ui.lnRunCycle.setText("On")
else:
self.ui.lnRunCycle.setText("Off")
# self.ui..setText(str(listRegValue[6])) #LEVEL_RESET
# self.ui..setText(str(listRegValue[7])) #CYL_MAN_CYCLE
# self.ui..setText(str(listRegValue[8])) #CYL_EMPTY
# self.ui..setText(str(listRegValue[9])) #CYL_EMPTY_END
# self.ui..setText(str(listRegValue[10])) #NORASYSTEM_MANUAL
# self.ui..setText(str(listRegValue[11])) #NORASYSTEM_ON
# self.ui..setText(str(listRegValue[12])) #HEATING_ALLOW
if str(listRegValue[13]) == "1": #LOW_AIRFLOW
self.ui.lnLowAirflow.setText("Low")
else:
self.ui.lnLowAirflow.setText("Normal")
# self.ui..setText(str(listRegValue[15])) #HUM_ALLOW
TC1 = listRegValue[16] / 100
self.ui.lnTC1.setText(str(TC1)+" °C") #TC1
TC2 = listRegValue[17] / 100
self.ui.lnTC2.setText(str(TC2)+" °C") #TC2
TC3 = listRegValue[18] / 100
self.ui.lnTC3.setText(str(TC3)+" °C") #TC3
TC4 = listRegValue[19] / 100
self.ui.lnTC4.setText(str(TC4)+" °C") #TC4
self.ui.lnH1.setText(str(listRegValue[20])+" %RH") #HUM1
waitTime = str(listRegValue[22] / 3600)
self.ui.lnWaitTime.setText(str(waitTime+" hr")) #WAIT_TIME_D
runTime = str(listRegValue[23] / 60)
self.ui.lnRunTime.setText(str(runTime+" min")) #RUN_TIME_D
timeRemainM = str(int(listRegValue[24] / 60))
timeRemainS = str(int(listRegValue[24] % 60))
self.ui.lnTimeRemain.setText(str(timeRemainM + " min "+timeRemainS + " sec")) #TIME_REMAIN_D
self.ui.lnLevel.setText(str(listRegValue[25])) #LEVEL_D
self.statusBar().showMessage("Modbus communication OK")
else:
self.statusBar().showMessage("Error modbus communication")
The problem come from this function after many try and error method. If I delete it program doesn't crash BUT if I modify it by print function (example: print(str(listRegValue[4]))) all is good so my problem doesn't come from mGUI assignation odbus module.
my function displayModbus is refresh every 5 second (using QtThreading).
If I keep just one variable to display my app doesn't crash.
I have another app to read and record modbus data using same displayModbus function (without QT5 display) and I haven't problem
I have this problem on 2 computers and I try it on 5 computers (4x windows 10 and 1x Linux)
Python 3.8.6
PyQT==5.15.1
PyQt5-sip==12.8.1
Any idea?
Thanks.
I'm relatively new to Python and I'm attempting to make a fun little project using Pyautogui and Python3.6. The goal of this project is to create a tensorflow powered project that learns to play chess. The problem I am now encountering is that whenever I try to use any of the pixel commands - e.g. pyautogui.pixel(...) or screenshot.getpixel(...) - an error pops up and says this:
Traceback (most recent call last):
File "main.py", line 109, in <module>
Score()
File "main.py", line 100, in Score
if gui.pixelMatchesColor(tempX, tempY, (87, 83, 82), tolerance=20):
File "/Users/student/Library/Python/3.6/lib/python/site-packages/pyscreeze/__init__.py", line 413, in pixelMatchesColor
pix = pixel(x, y)
File "/Users/student/Library/Python/3.6/lib/python/site-packages/pyscreeze/__init__.py", line 436, in pixel
return RGB(*screenshot().getpixel((x, y)))
TypeError: __new__() takes 4 positional arguments but 5 were given
I just want to note that all other commands work fine and that it's only the pixel ones that don't work.
I have installed everything including pyautogui(duh), pyscreeze, pymsgbox, pytweening, xlib, opencv, and any other package I could think of. These were installed using this command: pip3 install package-name-here --user. I needed the --user because I don't currently have administrator rights to my computer so I'm wondering if that could have something to do with my current predicament.
I also encountered an earlier post in my search for an answer but I forgot where I found it, so I'm sorry but I can't link it, but basically it said that I should go through and remove all pycache folders. I did this using the terminal command in the ~/Library/Python/3.6 folder:
find . -name "__pycache__" -type f -o -name "__pycache__" -type d -exec rm -rf {} \
I am in no need of an exact solution to this problem, but I'm wondering if there's some way to use the pyautogui.pixelMatchesColor(...) function or any similar one that you recommend that can have a tolerance - e.g. that the RGB values can be 10 units off and still return true.
For those of you that are interested, here is my full code:
#
# IMPORT ALL NECESSARY THINGS
#
import os, time, sys, pyautogui as gui, argparse as arg
#
# FAILSAFES
#
gui.FAILSAFE = True
gui.PAUSE = 0.1
#
# SET UP ARGUMENT PARSER
#
parser = arg.ArgumentParser(description='A machine learning script powered by TensorFlow designed to be run on "chess.com" using Python.')
parser.add_argument("-s", "--sleep", nargs='?', type=int, default='5', help='Number of seconds that the program should sleep before starting. This gives you time to move over to the website before the program looks for the gamboard on screen.')
args = parser.parse_args()
#
# ASKS USER FOR WHAT SIDE IT IS ON
#
side = input("Are you white or black? ")
if side == "W" or side == "w" or side == "white" or side == "White":
side = "W"
elif side == "B" or side == "b" or side == "black" or side == "Black":
side = "B"
else:
print("Invalid selection for which side!")
side = None
sys.exit(0)
#
# PRINT "READY" AND THEN WAIT FOR SPECIFIED AMOUNT OF TIME - DEFAULT 5 SECONDS
#
print("Ready! Waiting for " + str(args.sleep) + " seconds!")
time.sleep(int(args.sleep))
#
# GET AREA OF GAMEBOARD ON SCREEN
#
if side == "W":
gameboard = gui.locateOnScreen('./img/white/chessboard_white.png', confidence=0.55, grayscale=True)
left = gameboard.left - 10
top = gameboard.top - 5
right = gameboard.left + gameboard.width + 10
bottom = gameboard.top + gameboard.height + 15
elif side == "B":
gameboard = gui.locateOnScreen('./img/black/chessboard_black.png', confidence=0.55, grayscale=True)
left = gameboard.left - 10
top = gameboard.top - 5
right = gameboard.left + gameboard.width + 10
bottom = gameboard.top + gameboard.height + 15
widthInterval = (right - gameboard.left) / 8
heightInterval = (bottom - gameboard.top) / 8
#
# DEFINES A FUNCTION THAT COUNTS THE SCORE
# - NUMBER OF YOU SIDE AND THEN SUBTRACT THE NUMBER OF OPPOSITE SIDE
#
def Score():
for i in range(8):
for j in range(8):
tempX = 32 + (i * widthInterval)
tempY = 32 + (j * heightInterval)
if gui.pixelMatchesColor(tempX, tempY, (87, 83, 82), tolerance=20):
print("True!")
if side == "W":
print("White!")
elif side == "B":
print("Black!")
Score()
Note: The problem occurs in the last 10ish lines of the above code.
Thank you so much for your help and please don't hesitate to let me know if you need any more info from me!
Max
In visual studio I am trying to upload my code onto the ev3de (which is in python). It does work but as soon as I try to run it on the ev3, the program goes straight back to the screen before. When I try and run the program there are a few errors: It cannot find a module called pyev3, which I have never heard of, and it also cannot find the cwiid module, for the wiimote. Here is the code (it's not from myself):
#!/usr/bin/env python3
# Drive your robot with a wii remote!
# Left motor on port B, right motor on port C,
# vertical arm on port D.
# Requires the package 'python-cwiid'.
# Make sure bluetooth is enabled in brickman
# before trying to use this. Hold 2 to go forward
# and 1 to go backward.
import sys
import os
import time
import cwiid
import pyev3
def clamp(value, lower, upper):
return min(upper, max(value, lower))
print('press 1+2 on the wiimote now')
time.sleep(1)
w = cwiid.Wiimote()
print('connected?')
w.led = 6
w.rpt_mode = cwiid.RPT_ACC | cwiid.RPT_BTN
left_motor = pyev3.Motor(pyev3.OUTPUT_B)
left_motor.reset()
left_motor.run_mode = 'forever'
left_motor.regulation_mode = 'on'
right_motor = pyev3.Motor(pyev3.OUTPUT_C)
right_motor.reset()
right_motor.run_mode = 'forever'
right_motor.regulation_mode = 'on'
arm = pyev3.Motor(pyev3.OUTPUT_D)
arm.reset()
arm.run_mode = 'forever'
arm.regulation_mode = 'off'
target_distance = 8
top_speed = 720
left_motor.run = 1
right_motor.run = 1
last_btn_state = 0
move = 0
try:
while True:
state = w.state
buttons = state['buttons']
if buttons != last_btn_state:
if buttons & cwiid.BTN_MINUS:
top_speed -= 10
print (top_speed)
if buttons & cwiid.BTN_PLUS:
top_speed += 10
print (top_speed)
if buttons & cwiid.BTN_2:
move = 1
elif buttons & cwiid.BTN_1:
move = -1
else:
move = 0
if buttons & cwiid.BTN_LEFT:
arm.duty_cycle_sp = 100
arm.run = 1
elif buttons & cwiid.BTN_RIGHT:
arm.duty_cycle_sp = -100
arm.run = 1
else:
arm.run = 0
print (top_speed, move)
last_btn_state = buttons
if move:
acc = state['acc']
tilt = (clamp(acc[1], 95, 145) - 120) / 25.0 # roughly between -0.5 and 0.5
turn = top_speed * tilt
turn = clamp(turn, -abs(top_speed), abs(top_speed))
left_motor.pulses_per_second_sp = int(top_speed - turn) * move
right_motor.pulses_per_second_sp = int(top_speed + turn) * move
else:
left_motor.pulses_per_second_sp = 0
right_motor.pulses_per_second_sp = 0
finally:
left_motor.run = 0
right_motor.run = 0
When I run this one in Visual Studio Code, this happens:
File "c:/Users/User/Documents/fingers_crossed/drive.py", line 13, in
import cwiid ModuleNotFoundError: No module named 'cwiid' PS
C:\Users\User\Documents\fingers_crossed>
Also, why can't my robot find the ev3dev2 module?
My example code from google.
#!/usr/bin/env python
import pygame
from pygame import
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
# Initialise the pygame library
pygame.init()
# Connect to the first JoyStick16:11:10:05:0B:1C
j = pygame.joystick.Joystick(0)
j.init()
print 'Initialized Joystick : %s' % j.get_name()
# Setup the various GPIO values, using the BCM numbers for now
MotorA0 = 16
MotorA1 = 18
MotorAE = 22
MotorB0 = 23
MotorB1 = 21
MotorBE = 19
16:11:10:05:0B:1C
A0 = False
A1 = False
B0 = False
B1 = False
GPIO.setup(MotorA0,GPIO.OUT)
GPIO.setup(MotorA1,GPIO.OUT)
GPIO.setup(MotorAE,GPIO.OUT)
GPIO.setup(MotorB0,GPIO.OUT)
GPIO.setup(MotorB1,GPIO.OUT)
GPIO.setup(MotorBE,GPIO.OUT)
# Set all the Motors to 'off'
GPIO.output(MotorA0, A0)
GPIO.output(MotorA1, A1)
GPIO.output(MotorAE, False)
GPIO.output(MotorBE, False)
GPIO.output(MotorB0, B0)
GPIO.output(MotorB1, B1)
# Only start the motors when the inputs go above the following threshold
threshold = 0.60
LeftTrack = 0
RightTrack = 0
# Configure the motors to match the current settings.
def setmotors():
GPIO.output(MotorA0, A0)
GPIO.output(MotorA1, A1)
GPIO.output(MotorAE, True)
GPIO.output(MotorBE, True)
GPIO.output(MotorB0, B0)
GPIO.output(MotorB1, B1)
# Try and run the main code, and in case of failure we can stop the motors
try:
# Turn on the motors
GPIO.output(MotorAE, True)
GPIO.output(MotorBE, True)
# This is the main loop
while True:
# Check for any queued events and then process each one
events = pygame.event.get()
for event in events:
UpdateMotors = 0
# Check if one of the joysticks has moved
if event.type == pygame.JOYAXISMOTION:
if event.axis == 1:
LeftTrack = event.value
UpdateMotors = 1
elif event.axis == 3:
RightTrack = event.value
UpdateMotors = 1
# Check if we need to update what the motors are doing
if UpdateMotors:
# Check how to configure the left motor
# Move forwards
if (RightTrack > threshold):
A0 = False
A1 = True
# Move backwards
elif (RightTrack < -threshold):
A0 = True
A1 = False
# Stopping
else:
A0 = False
A1 = False
# And do the same for the right motor
if (LeftTrack > threshold):
B0 = False
B1 = True
# Move backwards
elif (LeftTrack < -threshold):
B0 = True
B1 = False
# Otherwise stop
else:
B0 = False
B1 = False
# Now we've worked out what is going on we can tell the
# motors what they need to do
setmotors()
except KeyboardInterrupt:
# Turn off the motors
GPIO.output(MotorAE, False)
GPIO.output(MotorBE, False)
j.quit()#!/usr/bin/env python
GPIO.cleanup()
When i run this code, i have a troubleshoot.
Traceback (most recent call last):
File "control.py", line 13, in
j = pygame.joystick.Joystick()
TypeError: function takes exactly 1 argument (0 given)
Your issue is that the command line j=pygame.joystick.Joystick(0) is calling the first ps3 controller that is available and paired to your raspberry pi (or whatever device you are using).
With that said, if you do not have a ps3 controller paired with the device, it will never work, because the next command line calls the Ps3controller 0 , and in your case, seems not to be any installed or paired.
Also some other issues with your code:
Line 4: Erase this line completely
Line 26: This was suppose to have a # hashtag before it, used only for notation. You can actually delete this line because it was notes from someone else's project anyway.
Line 78: The indentation is incorrect. it has to follow the indentation of the "while True" loop above it. So to fix it, make sure to backspace the command in line 78 all the way to the left, then press spacebar 8 times, or press TAB key 2 times, same thing. that will fix it!
Now your code works. actually one last thing, make sure to install pygame library as well, type this in the Xterminal(im using raspberry pi with raspbian) if u don't have it yet: sudo apt-get install python-pygame
I hope this all helped. I know you will have more questions, this code used to piss me off!lol