python script for 4x4 keypad, some buttons not workin - python-3.x

I'm trying to use a python script to make a connection with my 4x4 keypad on Rastberry (RPi.GPIO).
The code does not work correctly, because the first and second rows does not respond. I'm trying to use pad4pi, but in my case, this not work.
This is the code I'm using in the moment.
(Main Control)
import RPi.GPIO as GPIO
import time
import serial
import Keypad
#import Open_CV
ROWS = 4 # number of rows of the Keypad
COLS = 4 #number of columns of the Keypad
keys = [ '1','2','3','A', #key code
'4','5','6','B',
'7','8','9','C',
'*','0','#','D' ]
rowsPins = [18,22,29,31] #connect to the row pinouts of the keypad
colsPins = [32,33,36,37] #connect to the column pinouts of the keypad
# the pins need to be these, because the others are already in use
# Configure the use of the serial terminal and the baud rate
ser = serial.Serial( #"/dev/ttyS0", 9600)
port='/dev/ttyS0', #Replace ttyS0 with ttyAM0 for Pi1,Pi2,Pi0
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1)
#ConfiguraĆ§Ć£o inicial dos terminais GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
# call the video method
#video("teste.mp4")
def loop():
keypad = Keypad.Keypad(keys,rowsPins,colsPins,ROWS,COLS) #create Keypad object
keypad.setDebounceTime(50) #set the debounce time
# call the video method
#video('/home/pi/share/teste.mp4')
while(True):
key = keypad.getKey() #obtain the state of keys
if(key != keypad.NULL): #if there is key pressed, print its key code.
print ("You Pressed Key : %c "%(key))
ser.write(str.encode(key))
time.sleep(1)
#ret, frame = cap.read()
#gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#cv2.imshow('frame',gray)
#if cv2.waitKey(1) & 0xFF == ord('q'):
# break
#cap.release()
#cv2.destroyAllWindows()
if __name__ == '__main__': #Program start from here
print ("Program is starting ... ")
try:
loop()
except KeyboardInterrupt: #When 'Ctrl+C' is pressed, exit the program.
GPIO.cleanup()
(keypad functions)
#!/usr/bin/env python3
########################################################################
# Filename : Keypad.py
# Description : The module of matrix keypad
# Author : freenove
# modification: 2016/07/13
########################################################################
import RPi.GPIO as GPIO
import time
#class Key:Define some of the properties of Key
class Key(object):
NO_KEY = '\0'
#Defines the four states of Key
IDLE = 0
PRESSED = 1
HOLD = 2
RELEASED = 3
#define OPEN and CLOSED
OPEN = 0
CLOSED =1
#constructor
def __init__(self):
self.kchar = self.NO_KEY
self.kstate = self.IDLE
self.kcode = -1
self.stateChanged = False
class Keypad(object):
NULL = '\0'
LIST_MAX = 10 #Max number of keys on the active list.
MAPSIZE = 10 #MAPSIZE is the number of rows (times 16 columns)
bitMap = [0]*MAPSIZE
key = [Key()]*LIST_MAX
holdTime = 500 #key hold time
holdTimer = 0
startTime = 0
#Allows custom keymap, pin configuration, and keypad sizes.
def __init__(self,usrKeyMap,row_Pins,col_Pins,num_Rows,num_Cols):
GPIO.setmode(GPIO.BOARD)
self.rowPins = row_Pins
self.colPins = col_Pins
self.numRows = num_Rows
self.numCols = num_Cols
self.keymap = usrKeyMap
self.setDebounceTime(10)
#Returns a single key only. Retained for backwards compatibility.
def getKey(self):
single_key = True
if(self.getKeys() and self.key[0].stateChanged and (self.key[0].kstate == self.key[0].PRESSED)):
return self.key[0].kchar
single_key = False
return self.key[0].NO_KEY
#Populate the key list.
def getKeys(self):
keyActivity = False
#Limit how often the keypad is scanned.
if((time.time() - self.startTime) > self.debounceTime*0.001):
self.scanKeys()
keyActivity = self.updateList()
self.startTime = time.time()
return keyActivity
#Hardware scan ,the result store in bitMap
def scanKeys(self):
#Re-intialize the row pins. Allows sharing these pins with other hardware.
for pin_r in self.rowPins:
GPIO.setup(pin_r,GPIO.IN,pull_up_down = GPIO.PUD_UP)
#bitMap stores ALL the keys that are being pressed.
for pin_c in self.colPins:
GPIO.setup(pin_c,GPIO.OUT)
GPIO.output(pin_c,GPIO.LOW)
for r in self.rowPins: #keypress is active low so invert to high.
self.bitMap[self.rowPins.index(r)] = self.bitWrite(self.bitMap[self.rowPins.index(r)],self.colPins.index(pin_c),not GPIO.input(r))
#Set pin to high impedance input. Effectively ends column pulse.
GPIO.output(pin_c,GPIO.HIGH)
GPIO.setup(pin_c,GPIO.IN)
#Manage the list without rearranging the keys. Returns true if any keys on the list changed state.
def updateList(self):
anyActivity = False
kk = Key()
#Delete any IDLE keys
for i in range(self.LIST_MAX):
if(self.key[i].kstate == kk.IDLE):
self.key[i].kchar = kk.NO_KEY
self.key[i].kcode = -1
self.key[i].stateChanged = False
# Add new keys to empty slots in the key list.
for r in range(self.numRows):
for c in range(self.numCols):
button = self.bitRead(self.bitMap[r],c)
keyChar = self.keymap[r * self.numCols +c]
keyCode = r * self.numCols +c
idx = self.findInList(keyCode)
#Key is already on the list so set its next state.
if(idx > -1):
self.nextKeyState(idx,button)
#Key is NOT on the list so add it.
if((idx == -1) and button):
for i in range(self.LIST_MAX):
if(self.key[i].kchar == kk.NO_KEY): #Find an empty slot or don't add key to list.
self.key[i].kchar = keyChar
self.key[i].kcode = keyCode
self.key[i].kstate = kk.IDLE #Keys NOT on the list have an initial state of IDLE.
self.nextKeyState(i,button)
break #Don't fill all the empty slots with the same key.
#Report if the user changed the state of any key.
for i in range(self.LIST_MAX):
if(self.key[i].stateChanged):
anyActivity = True
return anyActivity
#This function is a state machine but is also used for debouncing the keys.
def nextKeyState(self,idx, button):
self.key[idx].stateChanged = False
kk = Key()
if(self.key[idx].kstate == kk.IDLE):
if(button == kk.CLOSED):
self.transitionTo(idx,kk.PRESSED)
self.holdTimer = time.time() #Get ready for next HOLD state.
elif(self.key[idx].kstate == kk.PRESSED):
if((time.time() - self.holdTimer) > self.holdTime*0.001): #Waiting for a key HOLD...
self.transitionTo(idx,kk.HOLD)
elif(button == kk.OPEN): # or for a key to be RELEASED.
self.transitionTo(idx,kk.RELEASED)
elif(self.key[idx].kstate == kk.HOLD):
if(button == kk.OPEN):
self.transitionTo(idx,kk.RELEASED)
elif(self.key[idx].kstate == kk.RELEASED):
self.transitionTo(idx,kk.IDLE)
def transitionTo(self,idx,nextState):
self.key[idx].kstate = nextState
self.key[idx].stateChanged = True
#Search by code for a key in the list of active keys.
#Returns -1 if not found or the index into the list of active keys.
def findInList(self,keyCode):
for i in range(self.LIST_MAX):
if(self.key[i].kcode == keyCode):
return i
return -1
#set Debounce Time, The defaul29t is 50ms
def setDebounceTime(self,ms):
self.debounceTime = ms
#set HoldTime,The default is 500ms
def setHoldTime(self,ms):
self.holdTime = ms
#
def isPressed(self, keyChar):
for i in range(self.LIST_MAX):
if(self.key[i].kchar == keyChar):
if(self.key[i].kstate == self.self.key[i].PRESSED and self.key[i].stateChanged):
return True
return False
#
def waitForKey(self):
kk = Key()
waitKey = kk.NO_KEY
while(waitKey == kk.NO_KEY):
waitKey = self.getKey()
return waitKey
def getState(self):
return self.key[0].kstate
#
def keyStateChanged(self):
return self.key[0].stateChanged
def bitWrite(self,x,n,b):
if(b):
x |= (1<<n)
else:
x &=(~(1<<n))
return x
def bitRead(self,x,n):
if((x>>n)&1 == 1):
return True
else:
return False

Related

PyInstaller creates an exe file, it works for the menu but it doesn't work for the actual program

Okay so I'm using pyinstaller to create an exe file for my python project to run, but when I run it, the exe file will open up my menu, and it will work perfectly fine, but when I select an option, it will clear the screen and then close the program. The program works perfectly well when run from command line. Below is the menu that I using pyinstaller on.
from pick import pick
import subprocess
def select_difficulty():
title = "Welcome to LowKeyBored's implementation of Typing Test (Rev 0)!"+'\nSelect difficulty'
options = ['Easy','Medium','Hard']
option, index = pick(options, title)
return option
def set_difficulty():
diff_args = ['-v']
difficulty = select_difficulty()
if difficulty == 'Easy':
diff_args.append('easy')
elif difficulty == 'Medium':
diff_args.append('medium')
else:
diff_args.append('hard')
return diff_args
def main():
diff_args = set_difficulty()
launch_args = ['python3','runner.py']+diff_args
subprocess.run(launch_args)
main()
runner .py
import typing_test
typing_test.main()
typingtest.py
"""
Copyright (c) 2019 Emil Lynegaard
Distributed under the MIT software license, see the
accompanying LICENSE.md or https://opensource.org/licenses/MIT
Minimal 10fastfingers like typing game for Python2/3 with ncurses.
Supports vocab files as arguments, as well as adjustable
word length, game time and word frequency (if using sorted vocab).
"""
import argparse
import time
import random
import curses
import textwrap
import os
# Robust path to default vocabulary, which is based on word frequency
# from CNN and DailyMail articles.
VOCAB_PATH = os.path.join(os.path.dirname(__file__), "data", "vocab")
# Used for WPM calculation
CHARS_PER_WORD = 5
# Amount of words to store, for showing several future words
# Should generally be equal to at least two lines worth of words
QUEUE_SIZE = 30
# Maximum amount of characters to be displayed in a single row
MAX_WIDTH = 80
# pylint: disable=too-many-instance-attributes
class Game:
"""
Class encapsulating the Game.
Includes game stats, input management, game display.
"""
CORRECT_COLOR = 1
INCORRECT_COLOR = 2
def __init__(self, args):
self.word_generator = self._word_generator(args)
self.game_time = args.game_time
self.next_words = [self._get_word() for _ in range(QUEUE_SIZE)]
self.typed = []
self.correct = []
self.incorrect = []
self.input = ""
self.display = args.display
# if using 10ff display, we keep track of extra things
if self.display == "10ff":
self.offset = 0
self.current_line = []
self.next_line = []
#staticmethod
def _word_generator(args):
words = []
for line in open(os.path.join(os.path.dirname(__file__), "data",args.vocab)):
word = line.strip()
if args.min_length <= len(word) <= args.max_length:
words.append(word)
if len(words) >= args.words:
break
if args.mode == "word":
while True:
yield random.choice(words)
else:
while True:
yield from words
def calculate_cpm(self, time_played):
"""Calculate CPM given time_played in seconds"""
if time_played == 0:
return 0
correct_chars = len(" ".join(self.correct))
cpm = 60 / time_played * correct_chars
cpm = int(round(cpm))
return cpm
def calculate_wpm(self, time_played):
"""Calculate WPM given time_played in seconds"""
cpm = self.calculate_cpm(time_played)
wpm = cpm // CHARS_PER_WORD
return wpm
def _get_word(self):
return next(self.word_generator)
def _finish_word_event(self):
target = self.next_words.pop(0)
self.typed.append(self.input)
if self.input == target:
self.correct.append(target)
else:
self.incorrect.append(target)
if self.display == "10ff":
self.offset += 1
self.next_words.append(self._get_word())
self.input = ""
#staticmethod
def _get_line(words, max_chars):
line = []
chars = 0
for word in words:
length = len(word)
# use +1 to account for added whitespace
if chars + length + 1 > max_chars:
break
line.append(word)
chars += length + 1
return line
def _progressive_display(self, stdscr, time_left):
_height, width = stdscr.getmaxyx()
width = min(width, MAX_WIDTH)
stdscr.clear()
wpm = self.calculate_wpm(self.game_time - time_left)
stdscr.addstr("Time left: {:d}, WPM: {:d}\n".format(time_left, wpm)+", Difficulty Level: "+self.difficulty_level+"\n")
line = self._get_line(self.next_words, width)
target = " ".join(line)
for idx, char in enumerate(self.input):
target_char = target[idx]
if target_char == char:
stdscr.addstr(char, curses.color_pair(self.CORRECT_COLOR))
else:
stdscr.addstr(target_char, curses.color_pair(self.INCORRECT_COLOR))
stdscr.addstr(target[len(self.input) : width - 1])
stdscr.addstr("\n" + self.input, curses.A_UNDERLINE)
stdscr.refresh()
def _10ff_display(self, stdscr, time_left):
_height, width = stdscr.getmaxyx()
width = min(width, MAX_WIDTH)
stdscr.clear()
wpm = self.calculate_wpm(self.game_time - time_left)
# stdscr.addstr("Time left: {:d}, WPM: {:d}".format(time_left, wpm)+", Difficulty Level: "+self.difficulty_level+"\n")
stdscr.addstr("Time left: {:d}, WPM: {:d}".format(time_left, wpm)+"\n")
# sets up initial lines
if not self.current_line:
self.current_line = self._get_line(self.next_words, width)
cur_len = len(self.current_line)
self.next_line = self._get_line(self.next_words[cur_len:], width)
# if we finished the current line
if self.offset >= len(self.current_line):
self.current_line = self.next_line
cur_len = len(self.current_line)
self.next_line = self._get_line(self.next_words[cur_len:], width)
self.offset = 0
# color the words already typed on current line
for i in range(self.offset):
target = self.current_line[i]
actual = self.typed[-(self.offset - i)]
if actual == target:
stdscr.addstr(target, curses.color_pair(self.CORRECT_COLOR))
else:
stdscr.addstr(target, curses.color_pair(self.INCORRECT_COLOR))
stdscr.addstr(" ")
stdscr.addstr(" ".join(self.current_line[self.offset :]))
stdscr.addstr("\n" + " ".join(self.next_line))
stdscr.addstr("\n" + self.input, curses.A_UNDERLINE)
stdscr.refresh()
def _update_display(self, stdscr, time_left):
if self.display == "progressive":
self._progressive_display(stdscr, time_left)
elif self.display == "10ff":
self._10ff_display(stdscr, time_left)
def _handle_key(self, key):
char = curses.keyname(key).decode()
if char == "^R":
self.restart()
if key in (curses.KEY_BACKSPACE, 127):
self.input = self.input[:-1]
elif chr(key) == " ":
self._finish_word_event()
else:
self.input += chr(key)
#staticmethod
def _setup_ncurses(stdscr):
# hide cursor
curses.curs_set(0)
# setup colors for printing text to screen
curses.use_default_colors()
curses.init_pair(Game.CORRECT_COLOR, curses.COLOR_GREEN, 0)
curses.init_pair(Game.INCORRECT_COLOR, curses.COLOR_RED, 0)
# don't wait for user input when calling getch()/getkey()
stdscr.nodelay(True)
# allow 100ms sleep on getch()/getkey() avoiding busy-wait
# early returns when key is pressed, meaning no input delay
stdscr.timeout(100)
def _game_loop(self, stdscr):
self._setup_ncurses(stdscr)
self._update_display(stdscr, self.game_time)
started = False
start = time.time()
time_left = self.game_time
while time_left > 0:
if not started:
start = time.time()
key = stdscr.getch()
new_time_left = int(round(self.game_time - (time.time() - start)))
if key == -1:
# only update display when necessary
if time_left != new_time_left:
time_left = new_time_left
self._update_display(stdscr, time_left)
continue
time_left = new_time_left
started = True
self._handle_key(key)
self._update_display(stdscr, time_left)
def print_stats(self):
"""Print ACC/CPM/WPM to console"""
correct = len(self.correct)
total = correct + len(self.incorrect)
accuracy = correct / total * 100
print("ACC: {:.2f}%".format(accuracy))
cpm = self.calculate_cpm(self.game_time)
print("CPM: {:d}".format(cpm))
wpm = self.calculate_wpm(self.game_time)
print("WPM: {:d}".format(wpm))
def restart(self):
"""
Reset the Game class, effective starting a new game
with new words, but based on same configuration.
"""
self.input = ""
self.correct = []
self.incorrect = []
self.typed = []
self.next_words = [self._get_word() for _ in range(QUEUE_SIZE)]
if self.display == "10ff":
self.offset = 0
self.current_line = []
self.next_line = []
self.play()
def play(self):
"""Start typing game and print results to terminal"""
curses.wrapper(self._game_loop)
self.print_stats()
def main():
"""Parse arguments and start game based thereof"""
parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter,
description=textwrap.dedent(
"""\
Start a minimal 10fastfingers-like typing game on the command line.
Keybinds:
CTRL+R: restart
CTRL+C: exit
"""
),
)
## replace this with the select-difficulty + language
parser.add_argument(
"-v",
"--vocab",
type=str,
metavar="vocab-file-path",
default=VOCAB_PATH,
help="path to newline separated vocab file",
)
parser.add_argument(
"-t",
"--game_time",
type=int,
metavar="gametime-seconds",
default=60,
help="duration in seconds of the typing game",
)
parser.add_argument(
"-min",
"--min_length",
type=int,
metavar="min-word-length",
default=1,
help="minimum word length",
)
parser.add_argument(
"-max",
"--max_length",
type=int,
metavar="max-word-length",
default=100,
help="maximum word length",
)
parser.add_argument(
"-w",
"--words",
type=int,
metavar="words-to-read",
default=200,
help="the amount of words to read from vocab - higher increases difficulty",
)
parser.add_argument(
"-a",
"--advanced",
action="store_const",
const=1000,
dest="words",
help="use 1000 most common words (corresponds to 10ff advanced mode)",
)
parser.add_argument(
"-d",
"--display",
type=str,
metavar="display",
default="10ff",
help="how to display words to type '10ff' or 'progressive'",
)
parser.add_argument(
"-m",
"--mode",
type=str,
metavar="mode-selection",
default="word",
help="selecting which mode you wish to play the game in",
)
args = parser.parse_args()
game = Game(args)
try:
game.play()
except KeyboardInterrupt:
pass
If anyone can give me advice on how to fix this that would help. Not sure if its the way I used pyinstaller or if its a problem with how I run a script within the first python file, and dependencies might not be implemented properly. Running the file give me the following:
This was simply a problem with directories. Pyinstaller put the executable file in it's own directory, where it couldn't import from the rest of my python files. I fixed it by dragging the executable into the directory with the rest of my python scripts. This is more of a temporary solution, as the executable has to be in the same directory as the other python files until I fix the import statements.

QTableWidget.setCellWidget creates windows of the given widget while using multi threading

So this code loads all the data from database and puts it in my table and works perfectly fine
it gets the data.
and if it is a combobox uses setCellWidget, and for normal text uses setItem:
output = LoadData(sql)
if output == []:
return False
for row in output:
row_pos = self.table.rowCount()
self.table.insertRow(row_pos)
for i, column in enumerate(row, 0):
normal_widget_item = True
item = QtWidgets.QTableWidgetItem(str(column))
# The 12 col is always a combobox
if i == 12:
item = QtWidgets.QComboBox()
item.addItems(self.all_messager_types)
item.setCurrentIndex(self.all_messager_types.index(column))
normal_widget_item = False
if i == 15:
flags = QtCore.Qt.ItemFlags()
flags != QtCore.Qt.ItemIsEnabled
item.setFlags(flags)
if normal_widget_item:
self.table.setItem(row_pos, i, item)
else:
self.table.setCellWidget(row_pos,i,item)
self.table.resizeColumnsToContents()
but when I try to use it in a different thread it creates new windows for every widget.
my thread class:
class load_table_thread(threading.Thread):
def __init__(self,target,sql=""):
super().__init__()
self.sql = sql
self.target = target
def run(self):
output = LoadData(self.sql)
if output == []:
return False
for row in output:
row_pos = self.target.table.rowCount()
self.target.table.insertRow(row_pos)
for i, column in enumerate(row, 0):
normal_widget_item = True
item = QtWidgets.QTableWidgetItem(str(column))
if i == 12:
item = QtWidgets.QComboBox()
item.addItems(self.target.all_messager_types)
item.setCurrentIndex(self.target.all_messager_types.index(column))
normal_widget_item = False
if i == 15:
flags = QtCore.Qt.ItemFlags()
flags != QtCore.Qt.ItemIsEnabled
item.setFlags(flags)
if normal_widget_item:
self.target.table.setItem(row_pos, i, item)
else:
self.target.table.setCellWidget(row_pos,i,item)
self.target.table.resizeColumnsToContents()
and this is the way I call it:
th = load_table_thread(self,sql)
th.start()
there is not errors in runtime but the program creates new windows for every combo box ( ignore the text, just look how many windows are open for the combobox ):
See the issue image
I used the pyqt threading system too but the same problem happens.

How would I tell if my user has focus on the terminal?

I am creating a chat room application using a CLI over a GUI, and I am on windows so I just use the default terminal in command prompt to run my code. My program detects individual key presses and then adds them to a list in my data class, which, when joined, creates the user's message. The only problem I'm having here is that the program records keypresses even when it is not in focus. Is there any way I can detect if the terminal is in focus or not so I can handle keypresses appropriately? What I have here at the moment is essentially an accidental keylogger of sorts.
My code (although not useful to the question I feel I should add it just in case):
import json, keyboard, os, socket, termcolor, threading
def addKey(key):
data.line.append(key)
data.lineLength += 1
def cls():
os.system("cls")
def display_chatLog():
return "\n".join(data.chatLog)
def display_lineLength():
return f"Characters: {data.lineLength}/{data.maxLineLength}\n\n"
def display_userInput():
return f"\n{data.start} {''.join(data.line)}{data.end}\n"
def enterPressed():
joinLine = " ".join(data.line)
if data.server:
if data.lineLength <= data.maxLineLength:
data.server.send(bytes(f"{data.username}: {joinLine}", "utf-8"))
data.line = []
else:
data.warning = "Your message is too long"
else:
if data.line[0] == "host":
port = data.line[1]
else:
IP = data.line[1]
port = data.line[2]
def getKeys():
specialKeys = ("backspace", "ctrl", "enter", "esc", "shift", "right shift", "space")
while True:
key = keyboard.read_event()
keyType = key.event_type
keyName = key.name
if keyType == "down":
if keyName not in specialKeys:
addKey(keyName)
elif keyName == "backspace":
if len(data.line) > 0:
del data.line[len(data.line) - 1]
data.lineLength -= 1
elif keyName == "enter":
enterPressed()
elif keyName == "shift":
if keyboard.is_pressed(f"shift+{keyName}") and keyName not in specialKeys:
addKey(keyName.upper)
elif keyName == "space":
addKey(" ")
class data:
chatLog = []
end = "_"
line = []
lineLength = 0
maxLineLength = 512
server = None
start = ">>>"
warning = "Make sure to either host a server using 'host (port)' or join one by using 'join (IP adress) (port)'"
getKeys_thread = threading.Thread(target = getKeys)
getKeys_thread.start()
while True:
cls()
print(display_chatLog(), display_userInput(), display_lineLength(), "\n", termcolor.colored(data.warning, "red", "on_white"))
import ctypes
def getWindow():
hwnd = ctypes.windll.user32.GetForegroundWindow()
length = ctypes.windll.user32.GetWindowTextLengthW(hwnd)
buff = ctypes.create_unicode_buffer(length + 1)
ctypes.windll.user32.GetWindowTextW(hwnd, buff, length + 1)
return (buff.value, hwnd) # buff.value is the title of the window, hwnd is the window handle
This code which I got from here and edited slightly allows me to capture the name and window handle of the currently focused window.

Python VLC player.next() control

I'm writing a Jukebox program that plays media based on key combinations (A1, B2, C3, etc.). Everything works the way I expect with the exception of the "media_player.next()" command.
Let's say you queue up 3 songs. If you hit the "y" key, it skips the song as I'd expect. My issue is that once it gets to the 3rd song, if you hit "y" again, it will circle back to the first song. I don't want that. I want the "y" key to take you forward in the media list...if that is the last song in the media list, don't go to the next song. How do I know if that's the last song in the media list or how do you stop VLC from going back to the beginning?
#!/usr/bin/env python3
#
import os, sys, csv, vlc, time, serial
from pynput.keyboard import Key, Listener
#
# Set Defaults
#
DefaultUSBPath="/media/pi"
#
# Declare variables
#
USBDrive = None
Action = None
Playlist = []
SelectionCount = []
Sel_char = None
#
# Find the USB Drive
#
USBDrive = os.path.join(DefaultUSBPath, "USB30FD")
#
# Adding to playlist - Returns directory contents and adds to playlist
#
def addplaylist(track):
list = None
if os.path.isdir(os.path.join(USBDrive, track)):
files = [f for f in os.listdir(os.path.join(USBDrive, track)) if os.path.isfile(os.path.join(USBDrive, track, f))]
for f in files:
if list is None:
list = os.path.join(USBDrive, track, f)
else:
list = list + ";" + os.path.join(USBDrive, track, f)
else:
print ("Error(3) - Selection is invalid")
if list is None:
print ("Error(4) - Selection has no media")
return list
#
# MediaPlayer function
#
def vlc_WhatsPlaying():
pass
def vlc_SongStarted(event):
print("Started")
song = media_player.get_media_player().get_media().get_mrl() # return path of current playing media
print(song)
splittrack = song.split("/")
track = splittrack[-2]
print(track)
return
def vlc_SongFinished(event):
print("Finished")
song = media_player.get_media_player().get_media().get_mrl() # return path of current playing media
print(song)
splittrack = song.split("/")
track = splittrack[-2]
#media_list.remove_index(0)
#media_player.play_item_at_index(1)
return
#
# Define keyboard actions
#
def on_press(key):
global Action, player
try:
Sel_char = int(key.char)
except:
try:
Sel_char = str(key.char)
Sel_char = Sel_char.upper()
except:
Sel_char = None
if Sel_char == "Z":
return False
elif Sel_char == "Y":
print("Skip")
media_player.next()
elif type(Sel_char) == str:
Action = Sel_char
elif type(Sel_char) == int:
Plist = None
Action = Action + str(Sel_char)
print("Action: " + Action)
Plist = addplaylist(Action)
if Plist is not None:
if ";" in Plist:
print(Plist)
Plist = Plist.split(";")
for p in Plist:
media_list.add_media(p)
else:
media_list.add_media(Plist)
# find section in array and increase the count by one
if not media_player.is_playing():
media_player.play()
else:
print ("Error(4) - Selection has no media")
else:
pass
#
# Setting Up Media Player
#
# creating Instance class object
player = vlc.Instance('--no-xlib --quiet ') # no-xlib for linux and quiet don't complain
media_player = vlc.MediaListPlayer() # creating a media player object
media_list = player.media_list_new() # creating a new media list
media_player.set_media_list(media_list) # setting media list to the media player
new = player.media_player_new() # new media player instance
media_player.set_media_player(new) # setting media player to it
media_events = new.event_manager() # setting event handler
# setting up events
media_events.event_attach(vlc.EventType.MediaPlayerMediaChanged, vlc_SongStarted)
media_events.event_attach(vlc.EventType.MediaPlayerEndReached, vlc_SongFinished)
# Read keyboard input
#
print("Ready...")
with Listener(on_press=on_press) as listener:
listener.join()
#
# Program is shutting down
#
print ("")
print ("Have a nice day!")
print ("")
sys.exit()
As mentioned in my comment the MediaListEndReached doesn't appear to do anything for me, so running with the idea of the list being the easiest way of addressing the issue, the following code tests the list position of the item being played and exits, if the next or previous command attempts to pass beyond the end of the list.
You can achieve the same result simply tracking an index variable.
You may have to adjust the splitting of the mrl to match the entries in your list.
import vlc
import time
## pinched from vlc for keyboard input
import termios
import tty
import sys
mymedia = ["vp.mp3","vp1.mp3","happy.mp3"]
def getch(): # getchar(), getc(stdin) #PYCHOK flake
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
return ch
## end pinched code
def jukebox():
player.play_item_at_index(0)
m = player.get_media_player()
print("Playing - ",m.get_media().get_mrl())
while True:
k = getch()
if k == "n": #Next
media = m.get_media()
if media.get_mrl().rsplit("/",1)[1] == mymedia[-1]: #Next requested but already at the end
break
player.next()
if k == "p": #Previous
media = m.get_media()
if media.get_mrl().rsplit("/",1)[1] == mymedia[0]: #Previous requested but already at the beginning
break
player.previous()
if k == " ": #Pause
player.pause()
if k == "q": #Quit
player.stop()
return True
time.sleep(0.1)
state = player.get_state()
print(state,m.get_media().get_mrl())
print("End of list")
vlc_instance = vlc.Instance('--no-xlib --quiet ') # no-xlib for linux and quiet don't complain
player = vlc_instance.media_list_player_new()
Media = vlc_instance.media_list_new(mymedia)
player.set_media_list(Media)
print("Welcome to Jukebox")
print("Options - space = Play/Pause, n = Next, p = Previous, q = Quit")
print("Media",mymedia)
jukebox()

Send message when failed(Python)

Im trying to simulate two machines working, and failing at random times. When they fail they call assistance. These two machines is part of bigger system of different machines, which needs to know when its neighbor has failed to do its job.
So far, I have made the simulate of the two machines, but I cant figure out how to send messages to their neighbors without each machine needing to know the whole system?
This is what I have so far:
import simpy
import random
random_seed=42
MTTF = 3500
break_mean = 1 / MTTF
sim_time = 4 * 7*24*60 # 4 weeks 24/7
num_machines = 2
rep_time = 30
tpp = 20 #20 minutes to make each part
neighbour = 3 #How many should it send to?
#Creating a class called messaging which is an object.
class messaging(object):
#DEfing the initilizing function, and initilize self, Environment, and capacity which is set to infinity, by a simpy core-function.
def __init__(self, env, capacity=simpy.core.Infinity):
self.env = env
self.capacity = capacity
self.pipes = []
#Making a function which work on everything that is a part of the message. With name Put.
def put(self, value):
if not self.pipes: #How to get this error?
raise runtime_error('There are no output pipes.')
#Create a variable, events, store to it pipe values
events = broken_machine()
return self.env.all_of(events)
def get_output_conn(self):
#Set the capacity of pipe variable to store infinity.
pipe = simpy.Store(self.env, capacity=self.capacity)
#to each pipes, add(or append) pipe
self.pipes.append(pipe)
return pipe
def mesg_generator(number, env, out_pipe):
msg = ('Failed')
def message_reciever(name, env, in_pipe):
while True:
msg = yield in_pipe.get()
print("%s received message: %s" % (number, msg[1]))
def time_per_part():
return tpp
def ttf():
return random.expovariate(break_mean)
class Machine(object):
def __init__(self, env, number, repair):
#self.arg = arg
self.env = env
self.number = number
self.parts_made = 0
self.times_broken = 0
self.broken = False
self.process = env.process(self.working(repair))
env.process(self.broken_machine())
def working(self, repair):
while True:
work = time_per_part()
while work:
try:
begin = self.env.now
yield self.env.timeout(work)
work = 0
except simpy.Interrupt:
self.broken = True
work -= self.env.now - begin
with repair.request(priority = 1) as req:
yield req
yield self.env.timeout(rep_time)
self.times_broken +=1
yield message_reciever()
#print('Machine down')
self.broken = False #Machine fixed again
self.parts_made +=1
def broken_machine(self):
while True:
yield self.env.timeout(ttf())
if not self.broken:
self.process.interrupt()
def other_jobs(env, repair):
while True:
work = tpp
while work:
with repair.request(priority=2) as req:
yield req
try:
begin = env.now
yield env.timeout(work)
work = 0
except simpy.Interrupt:
work -= env.now - begin
print("This simulates machines 3 and 4 doing the same tasks.")
random.seed(random_seed)
env = simpy.Environment()
pipe = simpy.Store(env)
bc_pipe = messaging(env)
repair = simpy.PreemptiveResource(env, capacity = 1)
machines = [Machine(env, 'Machine %d' % i, repair)
for i in range(num_machines)]
env.process(other_jobs(env, repair))
env.run(until=sim_time)
#Show how many times each machine failed:
for machine in machines:
print("%s broke down %d times" %(machine.number, machine.times_broken))

Resources