How to change "ON/OFF" string data into 0/1? - python

I am monitoring and controlling a smart light bulb from my dashboard(User Interface Dashboard) and every time I open or close the light bulb it sends back a data that shows the light bulb is on or off, what I want to do is to change this "ON/OFF" data string in to binary of 1/0, is there anyway I can get 1 or 0 instead of 'ON/OFF'.
this is some of the API code I have used to control the light bulb
def identifyDevice(self):
identifyDeviceResult = False
print(" {0}Agent for {1} is identifying itself by doing colorloop. Please observe your lights"
.format(self.variables.get('agent_id', None), self.variables.get('model', None)))
try:
devicewasoff = 0
if self.get_variable('status') == "OFF":
devicewasoff = 1
self.setDeviceStatus({"status": "ON"})
elif self.only_white_bulb:
self.setDeviceStatus({"status": "OFF"})
if self.only_white_bulb is False:
self.setDeviceStatus({"effect": "colorloop"})
if self.only_white_bulb:
time_iden = 3
else:
time_iden = 10 # time to do identification
t0 = time.time()
self.seconds = time_iden
while time.time() - t0 <= time_iden:
self.seconds = self.seconds - 1
print("wait: {} sec".format(self.seconds))
time.sleep(1)
self.setDeviceStatus({"effect": "none"})
if devicewasoff == 1:
self.setDeviceStatus({"status": "OFF"})
else:
self.setDeviceStatus({"status": "ON"})
identifyDeviceResult = True
except:
print("ERROR: classAPI_PhilipsHue connection failure! # identifyDevice")
return identifyDeviceResult

If you can guarantee that the returned value is always one of 'ON' or 'OFF', you can use the fact that True and 1 are interchangeable
result = state == 'ON'
If you need some error handling, something like this might work.
if state in {'ON', 'OFF'}:
result = state == 'ON'
else:
# handle error state
If you need an int to serialise, call int with the result
>>> state_on = 'ON'
>>> state_off = 'OFF'
>>> int(state_on == 'ON')
1
>>> int(state_off == 'ON')
0

Related

Comparing two values every n second and run a code based on the current and previous compared results in a while loop in python

Here is something I am trying to do:
A is a value that is constantly changing, and B is a fixed value
compare A and B every 5 seconds
if A > B, do something
if A < B, do something else
but if the current compared result is the same as the previous one (like if the current result is A > B, and the previous result is also A > B), do nothing until the result changes.
repeat
I really don’t know what to do with the 4th one, could somebody give me a hint?
Huge thanks
As you have not mentioned any language preference, I am using python here.
import time
c = time.time()
if A>B:
state = True
''' Do the initial action for this state'''
elif A<B:
state = False
''' Do the initial action for this state'''
while True:
if (time.time() - c) >= 5:
c = time.time()
A = check_A() # some dummy function for illustration purpose
B = check_B() # some dummy function for illustration purpose
if A>B:
if not state:
state = True
''' Do something that you like '''
elif A<B:
if state:
state = False
''' Do something that you like '''
Here I have assumed that you do not want anything to happen when when A==B. The logic here that unless the state changes there will be no action for that particular state.
If here you do not want your code to be continuously running then you can use time.sleep(SLEEP_TIME).
import time
if A>B:
state = True
''' Do the initial action for this state'''
elif A<B:
state = False
''' Do the initial action for this state'''
while True:
time.sleep(5)
A = check_A() # some dummy function for illustration purpose
B = check_B() # some dummy function for illustration purpose
if A>B:
if not state:
state = True
''' Do something that you like '''
elif A<B:
if state:
state = False
''' Do something that you like '''
Store the previous comparision in a variable.
previousComparison = '';
while True:
time.sleep(5) # Sleep for 5 seconds
if a > b and previousComparision != 'AIsGreater':
#do 2.
previousComparision = 'AIsGreater'
if b > a and previousComparision = 'BIsGreater':
#do 3.
#previousComparision = 'BIsGreater'
You can just remember the previous value of B and compare it as well to determine if you need to do something
def update(val):
return (val + 7) % 1000 # example
A = 500
B = 0
previous_B = 100000
while True:
previous_B = B
B = update(B)
if previous_B < A and B > A:
print(B, 'Do something')
elif previous_B > A and B < A:
print(B, 'Do something else')
In order to do this, you can keep track of the previous result in an additional variable
import random
previous = None
a = 10
b = 2
i = 0
while(i < 20):
print (a, b)
if (a > b and previous != False):
print('do something')
elif (a < b and previous == False):
print('do something else')
previous = a < b
b = random.randint(0, 20)
i += 1

Resetting the count of variable in a while loop

from microbit import *
from ssd1306 import initialize, clear_oled
from ssd1306_stamp import draw_stamp
from ssd1306_img import create_stamp
from ssd1306_text import add_text
import utime as time
window = []
threshold = 550 # limit
count = 0
sample = 0
beat = False
start = False
good = create_stamp(Image.HAPPY)
bad = create_stamp(Image.SAD)
heart = create_stamp(Image.HEART)
values = []
def mean(datalist):
sum = 0
for i in datalist:
sum += i
if len(datalist) > 0:
return sum/len(datalist)
else:
return None
while True:
if button_a.was_pressed():
while True:
signal = pin1.read_analog()
window.append(signal)
avg = round(mean(window))
values.append(avg)
if len(window) == 11:
window.pop(0)
if beat is False and avg >= threshold+10:
beat = True
count += 1
display.show(Image.HEART, wait=False)
if count == 1:
t1 = time.ticks_ms()
if count == 11:
t2 = time.ticks_ms()
T = t2 - t1
bpm = round(600*1000/(T))
display.scroll(str(bpm))
initialize()
clear_oled()
add_text(0, 0, "Heart rate :")
add_text(0, 3, str(bpm) + " bpm")
if 60 <= bpm <= 100:
draw_stamp(38, 24, good, 1)
else :
draw_stamp(38, 24, bad, 1)
count = 0
sleep(2000)
if button_b.was_pressed():
break
count = 0
elif beat is True and avg <= threshold-10:
beat = False
display.clear()
sample += 1
if sample == 250:
threshold = mean(values)
values = []
sample = 0
sleep(20)
sleep(20)
This is the code connect to the microbit, and the function is about the heart rate sensor, which it will appear the average beat per minute when sensing 10 beats of the heart.
I am thinking of adding a function that if button b is pressed, the loop will pause, and press the button a to start again. I tried to add a break function in the loop, it worked when I click the button b, it pause the loop, however, the count of beat won't reset, and the time between the beat is also recorded although I break the loop.
Is there any way that I can break the loop and reset the count?
You should reset the counter before breaking. In your current code the line for the count is not executing since it breaks out before it reaches it.
if button_b.was_pressed():
count = 0
break

Ultrasonic sensor as counter

I am trying to code ultrasonic sensors to count the number of cars in a parking lot. I am relatively new to Python, so I am asking here for help.
I have three parking slots, in which each of them has an ultrasonic sensor.
How do I make it so that the sensors and their counters work together? For example, when the parking slots are empty, the counter shows three parking slots available. When two parking slots are filled, the counter shows one availability, etc.
I have done the following code, and I am wondering how I could continue to achieve my objective?
# Sensor 1
def distance_1():
time.sleep(0.5)
GPIO.output(TRIG_1, True)
time.sleep(0.00001)
GPIO.output(TRIG_1, False)
print("Reading Sensor 1")
while GPIO.input(ECHO_1) == 0:
start = time.time()
while GPIO.input(ECHO_1) == 1:
end = time.time()
duration = end - start
sound = 34000 / 2
distance = duration * sound
round(distance, 0)
total = 3
count = total
if distance <= 10:
count -= 1
elif distance > 10:
count += 1
if count < 0:
count = 0
elif count > total:
count = total
print(count)
mylcd.lcd_display_string("{}".format(count), 2)
# Sensor 2
def distance_2():
time.sleep(0.5)
GPIO.output(TRIG_2, True)
time.sleep(0.00001)
GPIO.output(TRIG_2, False)
print("Reading Sensor 2")
while GPIO.input(ECHO_2) == 0:
start = time.time()
while GPIO.input(ECHO_2) == 1:
end = time.time()
duration = end - start
sound = 34000 / 2
distance = duration * sound
round(distance, 0)
total = 3
count = total
if distance <= 10:
count -= 1
elif distance > 10:
count += 1
if count < 0:
count = 0
elif count > total:
count = total
print(count)
mylcd.lcd_display_string("{}".format(count), 2)
# Sensor 3
def distance_3():
time.sleep(0.5)
GPIO.output(TRIG_3, True)
time.sleep(0.00001)
GPIO.output(TRIG_3, False)
print("Reading Sensor 3")
while GPIO.input(ECHO_3) == 0:
start = time.time()
while GPIO.input(ECHO_3) == 1:
end = time.time()
duration = end - start
sound = 34000 / 2
distance = duration * sound
round(distance, 0)
total = 3
count = total
if distance <= 10:
count -= 1
elif distance > 10:
count += 1
if count < 0:
count = 0
elif count > total:
count = total
print(count)
mylcd.lcd_display_string("{}".format(count), 2)
while True:
distance_1()
distance_2()
distance_3()
GPIO.cleanup()
The trouble with programming is there are so many ways to achieve the same result.
Looking at your code, I would suggest taking a step back and refactoring it to use Python classes instead. You have a lot of code repetition happening, and eventually, the code will break if you need to keep adding more sensors.
For example:
class Parking:
"This is a parking class"
def __init__(self, space):
self.space = space
def empty(self):
if self.space == 0:
print('Parking space is empty')
def full(self):
if self.space == 1:
print('Parking space is full')
def distance(self):
time.sleep(0.5)
GPIO.output(TRIG, True)
. . .
# Input:
sensor1 = Parking(1)
sensor2 = Parking(1)
sensor3 = Parking(0)
# Output:
sensor1.empty()
sensor2.empty()
sensor3.empty()
# Output:
sensor1.full()
sensor2.full()
sensor3.full()
You can then update a dictionary with the output to monitor the latest sensor information. Ideally, the dictionary would be written to a central file accessible by all the sensors or raspberry pis to read.
available_spaces = {"sensor1": 0, "sensor2": 1, "sensor3": 0}
I analyzed your code and I did some refactorings.
I suggest you to use constant values initialization (the config section you see in the code below). The values I used are random.
A function can be parametrized, so you can pass arguments to functions, and avoid writing the same piece of code changing only a few values in the same place.
You should set up your microcontroller when the script starts, to tell the board how you are using the pins (as input or output).
I didn't dig into on the snippet above the lcd_display_string and why are you doing those operations. I suppose that these are required to print on screen the distance.
## configuration
# trigger
TRIG_1 = 17
TRIG_2 = 27
TRIG_3 = 22
# echo
ECHO_1 = 10
ECHO_2 = 9
ECHO_3 = 11
# timings
INITIAL_DELAY = 0.5
TRIGGERING_DELAY = 0.00001
## support functions
# initializing GPIO
def set_up():
# set trigger GPIOs as output pins
GPIO.setup(TRIG_1, GPIO.OUT)
GPIO.setup(TRIG_2, GPIO.OUT)
GPIO.setup(TRIG_3, GPIO.OUT)
# set echo GPIOs as input pins
GPIO.setup(ECHO_1, GPIO.IN)
GPIO.setup(ECHO_2, GPIO.IN)
GPIO.setup(ECHO_3, GPIO.IN)
# I didn't dig into these values and why are you doing these operations. I suppose that these are required to print on screen the distance.
def print_distance_on_lcd(distance):
total = 3
count = total
if distance <= 10:
count -= 1
elif distance > 10:
count += 1
if count < 0:
count = 0
elif count > total:
count = total
print(count)
mylcd.lcd_display_string("{}".format(count), 2)
def trigger(trigger):
time.sleep(INITIAL_DELAY)
GPIO.output(trigger, True) # set output pin on HIGH state
time.sleep(TRIGGERING_DELAY)
GPIO.output(trigger, False) # set output pin on LOW state
def distance(t, echo):
trigger(t)
# initializing the variables here, allows you to use it outside the while block below
# using variable names that explains their content
start_time = time.time()
end_time = time.time()
# this block is not wrong, but unnecessary: initializing the variable like above is enough
'''
while GPIO.input(echo) == 0:
start_time = time.time()
'''
while GPIO.input(echo) == 1:
end_time = time.time()
duration = end_time - start_time
sound = 34000 / 2
distance = duration * sound
return distance
# call initialization function (this will be executed only one time)
set_up()
# loop forever
while True:
set_up()
print("Reading Sensor 1")
distance_sensor_1 = distance(TRIG_1, ECHO_1)
print_distance_on_lcd(distance_sensor_1)
print("Reading Sensor 2")
distance_sensor_2 = distance(TRIG_2, ECHO_2)
print_distance_on_lcd(distance_sensor_2)
print("Reading Sensor 3")
distance_sensor_3 = distance(TRIG_3, ECHO_3)
print_distance_on_lcd(distance_sensor_3)
GPIO.cleanup()

Don't understand this timed while loop attribute error

So I have been trying to make a while loop that will run for 10 minutes. But is keeps erroring out on the line with the while loop. It says 'str' object has no attribute 'time'.
I have discovered that if i remove the lines with now.strftime() in them that the code runs but I don't know why it runs without those lines or how to fix it.
I did also try to do something using the datetime module instead of importing the time module but this also fails.
import math
from datetime import datetime
import time
test_num = 1
largest_loop = 0
delay = 60 * 10
end_time = time.time() + delay
def even_number(value):
if value == 2:
return True
def divide_five(value):
if value == 5:
return True
def is_square(value):
if math.sqrt(value).is_integer():
return False
def multiple_of(value):
if value == 2:
return True
def is_happy():
global check
if check == 1:
return True
while time.time() <= end_time:
test_num += 1
check = test_num
now = datetime.now()
loop_counter = 0
record_loop = 6
date = now.strftime("%m/%d/%Y")
time = now.strftime("%H:%M:%S")
if even_number(test_num) == True:
if divide_five(test_num) == True:
if is_square(test_num) == True:
for _ in range(record_loop + 4):
loop_counter += 1
if is_happy() == True:
if multiple_of(test_num) == True:
#print(test_num)
record_loop = loop_counter
break
else:
pass
else:
pass
else:
pass
else:
pass
else:
pass
As #CoryKramer pointed out, you named a variable time, which is also the name of the module you are importing. All I really did was change the time variable to something like currTime. Try the code below (runs for me):
import math
from datetime import datetime
import time
test_num = 1
largest_loop = 0
delay = 60 * 10
end_time = time.time() + delay
def even_number(value):
if value == 2:
return True
def divide_five(value):
if value == 5:
return True
def is_square(value):
if math.sqrt(value).is_integer():
return False
def multiple_of(value):
if value == 2:
return True
def is_happy():
global check
if check == 1:
return True
while time.time() <= end_time:
test_num += 1
check = test_num
now = datetime.now()
loop_counter = 0
record_loop = 6
date = now.strftime("%m/%d/%Y")
currTime = now.strftime("%H:%M:%S")
if even_number(test_num) == True:
if divide_five(test_num) == True:
if is_square(test_num) == True:
for _ in range(record_loop + 4):
loop_counter += 1
if is_happy() == True:
if multiple_of(test_num) == True:
#print(test_num)
record_loop = loop_counter
break
else:
pass
else:
pass
else:
pass
else:
pass
else:
pass
Additionally, consider reading up on:
How to name a module without conflict with variable name?
https://en.wikipedia.org/wiki/Variable_shadowing
dont name your variable in your while loop time when you import the time library:
time = now.strftime("%H:%M:%S")
in your while loop you want to use the time function of the time library but as soon as you run the while loop once it will try to use time() on the string time you defined in the while loop.
I think the problem is here:
time = now.strftime("%H:%M:%S")
Thus, you converted time into a string variable. Name this variable in a different way!
Apart from this, running for 10 minutes at "full throttle" is a lot! Consider to introduce a "sleep" time at the end of the while loop (just suggesting)

Monty Hall simulation not working as intended

I've been trying out to solve the monty hall problem in Python in order to advance in coding, which is why I tried to randomize everything. The thing is: I've been running into some trouble. As most of you probably know the monty problem is supposed to show that changing the door has a higher winrate (66%) than staying on the chosen door (33%). For some odd reason though my simulation shows a 33% winrate for both cases and I am not really sure why.
Here's the code:
from random import *
def doorPriceRandomizer():
door1 = randint(0,2) #If a door is defined 0, it has a price in it
door2 = randint(0,2) #If a door is defined either 1 or 2, it has a goat in it.
door3 = randint(0,2)
while door2 == door1:
door2 = randint(0,2)
while door3 == door2 or door3 == door1:
door3 = randint(0,2)
return door1,door2,door3 #This random placement generator seems to be working fine.
while True:
loopStart = 0
amountWin = 0
amountLose = 0
try:
loopEnd = int(input("How often would you like to run this simulation: "))
if loopEnd < 0:
raise ValueError
doorChangeUser = int(input("[0] = Do not change door; [1] = Change door: "))
if doorChangeUser not in range(0,2):
raise ValueError
except ValueError:
print("Invalid input. Try again.\n")
else:
while loopStart != loopEnd:
gameDoors = doorPriceRandomizer()
inputUser = randint(0,2)
if doorChangeUser == 0:
if gameDoors[inputUser] == 0:
amountWin += 1
loopStart += 1
else:
amountLose += 1
loopStart += 1
elif doorChangeUser == 1:
ChangeRandom = 0
while gameDoors[ChangeRandom] == gameDoors[inputUser]:
ChangeRandom = randint(0,2)
if gameDoors[ChangeRandom] == 0:
amountWin += 1
loopStart += 1
else:
amountLose += 1
loopStart += 1
print("Win amount: ",amountWin,"\tLose amount: ",amountLose)
What am I doing wrong? I really appreciate all help! Thanks in advance!
ChangeRandom = 0
while gameDoors[ChangeRandom] == gameDoors[inputUser]:
ChangeRandom = randint(0,2)
This doesn't do what you think it does. Instead of checking if the ChangeRandom door is the same as the inputUser door, this checks if the ChangeRandom door and the inputUser door have the same value -- that is to say they're either both winners or both losers.
That said, that's not even what you want to do. What you want to do is to find a door that's not the user's input that IS a loser door, then switch to the OTHER one that isn't the user's input. This could be implemented with minimal change to your code as:
other_wrong_door = next(c for c, v in enumerate(gameDoors) if v != 0 and c != inputUser)
new_door = next(c for c, _ in enumerate(gameDoors) if c != inputUser and c != other_wrong_door)
But honestly this merits a re-examining of your code's structure. Give me a few minutes to work something up, and I'll edit this answer to give you an idea of how I'd implement this.
import random
DOORS = [1, 0, 0]
def runonce(switch=False):
user_choice = random.choice(DOORS)
if user_choice == 1:
# immediate winner
if switch:
# if you won before and switch doors, you must lose now
return False
else:
new_doors = [0, 0] # remove the user-selected winner
new_doors = [0] # remove another loser
return bool(random.choice(new_doors))
# of course, this is always `0`, but
# sometimes it helps to show it. In production you
# wouldn't bother writing the extra lines and just return False
else:
if switch:
new_doors = [1, 0] # remove the user-selected loser
new_doors = [1] # remove another loser
return bool(random.choice(new_doors))
# as above: this is always True, but....
else:
return False # if you lost before and don't switch, well, you lost.
num_trials = int(input("How many trials?"))
no_switch_raw = [run_once(switch=False) for _ in range(num_trials)]
switch_raw = [run_once(switch=True) for _ in range(num_trials)]
no_switch_wins = sum(1 for r in no_switch_raw if r)
switch_wins = sum(1 for r in switch_raw if r)
no_switch_prob = no_switch_wins / num_trials * 100.0
switch_prob = switch_wins / num_trials * 100.0
print( " WINS LOSSES %\n"
f"SWITCH: {switch_wins:>4} {num_trials-switch_wins:>6} {switch_prob:.02f}\n"
f"NOSWITCH:{no_switch_wins:>4} {num_trials-no_switch_wins:>6} {no_switch_prob:.02f}")
You have gotten the mechanics of the problem wrong so you are getting the wrong result. I have rewritten the choice mechanics, but I am leaving the user input stuff to you so that you can continue to learn python. This is one of many ways to solve the problem, but hopefully it demonstrates some things to you.
def get_choices():
valid_choices = [0, 1, 2] # these are the values for a valid sample
shuffle(valid_choices) # now randomly shuffle that list
return valid_choices # return the shuffled list
def get_door(user_choice):
return user_choice.index(0)
def monty_sim(n, kind):
"""
:param n: number of runs in this simulation
:param kind: whether to change the door or not, 0 - don't change, 1 = change door
:return: (win_rate, 1 - win_rate)
"""
wins = 0
for i in range(0, n):
game_doors = get_choices()
user_choice = get_door(get_choices()) # use the same method and find user door choice
# so there are two branches.
# In both, a door with a goat (game_door = 1) is chosen, which reduce the result to
# a choice between two doors, rather than 3.
if kind == 0:
if user_choice == game_doors.index(0):
wins += 1
elif kind == 1:
# so now, the user chooses to change the door
if user_choice != game_doors.index(0):
wins += 1
# Because the original choice wasn't the right one, then the new
# must be correct because the host already chose the other wrong one.
win_rate = (wins / n) * 100
return win_rate, 100 - win_rate
if __name__ == '__main__':
n = 1000
kind = 1
wins, loses = monty_sim(n, kind)
print(f'In a simulation of {n} experiments, of type {kind} user won {wins:02f} of the time, lost {loses:02f} of the time')

Categories

Resources