Variables not displaying correctly - python-telegram-bot

I am using user_data[TO] = update.message.text to update variables as a user types information into the bot.
When it comes time to output those variables, it is only showing sequential numbers starting at 0.
FROM, TO, SEND, REVIEW = range(4)
user_data = {}
I am using this to store the variables.
and this to output them.
def review_handler(update: Update, context):
update.message.reply_text('*Review your Details* \n\n'
f'Data1 \+{FROM} \n'
f'Data2 \+{TO} \n\n'
'Press /yes to proceed and /cancel to exit', parse_mode='MarkdownV2')
I am getting output like Data1 +0 Data2 +1
and so on. Not sure what the issue is.

I figured it out. I needed to use {user_data[TO]} instead of just [TO]

Related

Catch multiple exceptions with specific error messages leading to one exit command

I'm trying to create a program that prompts the user for their weight in pounds as a float, when entered I need to check the entry to ensure that it is not a string or below the value of 10. It needs to be done in an if statement and not a loop, as well I need to be able to end multiple exceptions with one quit() statement instead of multiple quit() statements for each exception and then continue the program further if the user entered the input in the correct parameters.
This is what I have so far:
isvalid = float,int
try:
weight_pounds = float(input("Enter your weight in pounds: ")
if weight_pounds != isvalid:
print("Cannot be alphabetical.")
elif weight_pounds < 10:
print("Cannot be less than 10.")
else:
input("Press enter to exit...")
quit()
I am still learning basic functions of python and I may be missing something simple here but I've tried many ways to get this to work and I can't seem to get it working without either a dead end or ValueErrors.

Using Amazon Lex's inputTranscript to allow for an wide open slot. There is only one slot

Similar to the question that was asked previously amazon lex transcript wide open slot. This dealing with the solution to that question and the comment under the solution. The intent I want to create has only one slot and I just want to respond appropriately after receiving the reply from the user. in this case, if I don't want to use elicitSlot. What should I do?
I have got the first part down:
slots = intent_request['currentIntent']['slots']
slots['anyString'] = intent_request['inputTranscript']
I tried to use elixit_slot. But it will only prompt me for the same transcript again, which is not what I want.
I want to output a reply back to lex after the user entered a set of strings after the first time the inputTranscript is filled up.
I have a workaround for this problem:
if ChooseCase == 'Case 1' and CaseOneChosen == 'Yes' and not CaseOneQuestion:
# Assign current inputTranscript to slots
intent_request['currentIntent']['slots']['CaseOneQuestion'] = intent_request['inputTranscript']
CaseOneQuestion = intent_request['inputTranscript']
# After the user enter the text, check if the current slot value is the same as the previous slot,
# if it is, then this is the first time the user elicit this slot
# Else, assign the current inputTranscript to the current slot (done above)
if intent_request['currentIntent']['slots']['CaseOneQuestion'] == intent_request['currentIntent']['slots']['CaseOneChosen']:
return elicit_slot(
output_session_attributes,
intent_request['currentIntent']['name'],
intent_request['currentIntent']['slots'],
'CaseOneQuestion',
{'contentType': 'PlainText', 'content': 'Answer for case 1'},
None
)
Explain: The previous slot is "CaseOneChosen", the value is this slot is "Yes", then line 3 will assign that value to the slot "CaseOneQuestion". Now they both have the same value, so the if statement is TRUE. The bot will let the user elicit slot "CaseOneQuestion" (I assume the user entered "cat"). After this, line 3 will assign "cat" to "CaseOneQuestion" slot. So now the if statement is FALSE. the bot will not re-prompt to ask the user elicit "CaseOneQuestion" slot anymore. And the slot value is now "cat".
Hope this helps.

Loop until find the match in table

I have table and it updated every time if the loop didn't find the Match in table key.
for d in io.popen("ls -a /mnt/mediashare/net"):lines() do
OnlineCheck[#OnlineCheck+1] = d
end
First I add the values in to tables then I run another loop to find the match form it if it founds the match the loop breaks but if not then it should reload the table with new values and start matching again. I can't figured it out how to do this all in single loop.
for d1,d2 in pairs(OnlineCheck) do
if d2==NASFolder then
print("NAS Connected")
break
else
print("NAS is Offline")
end
end
In Lua 5.2 you should be able to do:
local connected = os.execute(('[ -d /mnt/mediashare/net/%q ]'):format(NASFolder))
(For Lua 5.1, compare os.execute()'s result with 0.)
You don't need to collect lines in table, perform match on the fly:
function findUntilMatch(NASFolder)
for line in io.popen("ls -a /mnt/mediashare/net"):lines() do
if line == NASFolder then
print("NAS Connected")
return
end
print("NAS is Offline")
return findUntilMatch(NASFolder) -- tail call recursion
end
Keep in mind - it may run forever ...
Update: I have reread the question and now I'm not sure what topic starter means as:
I can't figured it out how to do this all in single loop.
My original answer was the attempt to write all-in-single-loop including reread info from device.
It is also possible to perform the search by shell (inspired by another answer):
local connected = io.popen("ls -a /mnt/mediashare/net | grep '^" .. NASFolder .. "$'"):read()
Device reread logic is missed in this example.

Static lookup table (litteral bit map)

I am receiving some data which is parsed in a Ruby script, a sample of the parsed data looks like this;
{"address":"00","data":"FF"}
{"address":"01","data":"00"}
That data relates to the status (on/off) of plant items (Fans, coolers, heaters etc.) the address is a HEX number to tell you which set of bits the data refers to. So in the example above the lookup table would be; Both of these values are received as HEX as in this example.
Bit1 Bit2 Bit3 Bit4 Bit5 Bit6 Bit7 Bit8
Address 00: Fan1 Fan2 Fan3 Fan4 Cool1 Cool2 Cool3 Heat1
Address 01: Hum1 Hum2 Fan5 Fan6 Heat2 Heat3 Cool4 Cool5
16 Addresses per block (This example is 00-0F)
Data: FF tells me that all items in Address 00 are set on (high/1) I then need to output the result of the lookup for each individual bit e.g
{"element":"FAN1","data":{"type":"STAT","state":"1"}}
{"element":"FAN2","data":{"type":"STAT","state":"1"}}
{"element":"FAN3","data":{"type":"STAT","state":"1"}}
{"element":"FAN4","data":{"type":"STAT","state":"1"}}
{"element":"COOL1","data":{"type":"STAT","state":"1"}}
{"element":"COOL2","data":{"type":"STAT","state":"1"}}
{"element":"COOL3","data":{"type":"STAT","state":"1"}}
{"element":"HEAT1","data":{"type":"STAT","state":"1"}}
A lookup table could be anything up to 2048 bits (though I don't have anything that size in use at the moment - this is maximum I'd need to scale to)
The data field is the status of the all 8 bits per address, some may be on some may be off and this updates every time my source pushes new data at me.
I'm looking for a way to do this in code ideally for the lay-person as I'm still very new to doing much with Ruby. There was a code example here, but it was not used in the end and has been removed from the question so as not to confuse.
Based on the example below I've used the following code to make some progress. (note this integrates with an existing script all of which is not shown here. Nor is the lookup table shown as its quite big now.)
data = [feeder]
data.each do |str|
hash = JSON.parse(str)
address = hash["address"]
number = hash["data"].to_i(16)
binary_str = sprintf("%0.8b", number)
binary_str.reverse.each_char.with_index do |char, i|
break if i+1 > max_binary_digits
mouse = {"element"=>+table[address][i], "data"=>{"type"=>'STAT', "state"=>char}}
mousetrap = JSON.generate(mouse)
puts mousetrap
end
end
This gives me an output of {"element":"COOL1","data":{"type":"STAT","state":"0"}} etc... which in turn gives the correct output via my node.js script.
I have a new problem/query having got this to work and captured a whole bunch of data from last night & this morning. It appears that now I've built my lookup table I need some of the results to be modified based on the result of the lookup. I have other sensors which need to generate a different output to feed my SVG for example;
FAN objects need to output {"element":"FAN1","data":{"type":"STAT","state":"1"}}
DOOR objects need to output {"element":"DOOR1","data":{"type":"LAT","state":"1"}}
SWIPE objects need to output {"element":"SWIPE6","data":{"type":"ROUTE","state":"1"}}
ALARM objects need to output {"element":"PIR1","data":{"type":"PIR","state":"0"}}
This is due to the way the SVG deals with updating - I'm not in a position to modify the DOM stuff so would need to fix this in my Ruby script.
So to address this what I ended up doing was making an exact copy of my existing lookup table and rather than listing the devices I listed the type of output like so;
Address 00: STAT STAT STAT ROUTE ROUTE LAT LAT PIR
Address 01: PIR PIR STAT ROUTE ROUTE LAT LAT PIR
This might be very dirty (and it also means I have to duplicate my lookup table, but it actually might be better for my specific needs as devices within the dataset could have any name (I have no control over the received data) Having built a new lookup table I modified the code I had been provided with below and already used for the original lookup but I had to remove these 2 lines. Without removing them I was getting the result of the lookup output 8 times!
binary_str.reverse.each_char.with_index do |char, i|
break if i+1 > max_binary_digits
The final array was built using the following;
mouse = {"element"=>+table[address][i], "data"=>{"type"=>typetable[address][i], "state"=>char}}
mousetrap = JSON.generate(mouse)
puts mousetrap
This gave me exactly the output I require and was able to integrate with both the existing script, node.js websocket & mongodb 'state' database (which is read on initial load)
There is one last thing I'd like to try and do with this code, when certain element states are set to 1 I'd like to be able to look something else up (and then use that result) I'm thinking this may be best done with a find query to my MongoDB and then just use the result. Doing that would hit the db for every query, but there would only ever be a handful or results so most things would return null which is fine. Am I along the right method of thinking?
require 'json'
table = {
"00" => ["Fan1", "Fan2", "Fan3"],
"01" => ["Hum1", "Hum2", "Fan5"],
}
max_binary_digits = table.first[1].size
data = [
%Q[{"address": "00","data":"FF"}],
%Q[{"address": "01","data":"00"}],
%Q[{"address": "01","data":"03"}],
]
data.each do |str|
hash = JSON.parse(str)
address = hash["address"]
number = hash["data"].to_i(16)
binary_str = sprintf("%0.8b", number)
p binary_str
binary_str.reverse.each_char.with_index do |char, i|
break if i+1 > max_binary_digits
puts %Q[{"element":#{table[address][i]},"data":{"type":"STAT","state":"#{char}"}}}]
end
puts "-" * 20
end
--output:--
"11111111"
{"element":Fan1,"data":{"type":"STAT","state":"1"}}}
{"element":Fan2,"data":{"type":"STAT","state":"1"}}}
{"element":Fan3,"data":{"type":"STAT","state":"1"}}}
--------------------
"00000000"
{"element":Hum1,"data":{"type":"STAT","state":"0"}}}
{"element":Hum2,"data":{"type":"STAT","state":"0"}}}
{"element":Fan5,"data":{"type":"STAT","state":"0"}}}
--------------------
"00000011"
{"element":Hum1,"data":{"type":"STAT","state":"1"}}}
{"element":Hum2,"data":{"type":"STAT","state":"1"}}}
{"element":Fan5,"data":{"type":"STAT","state":"0"}}}
--------------------
My answer assumes Bit1 in your table is the least significant bit, if that is not the case remove .reverse in the code.
You can ask me anything you want about the code.

removing duplicates from list of strings (output from Twilio call - Ruby)

I'm trying to display total calls from a twilio object as well as unique calls.
The total calls is simple enough:
# set up a client to talk to the Twilio REST API
#sub_account_client = Twilio::REST::Client.new(#account_sid, #auth_token)
#subaccount = #sub_account_client.account
#calls = #subaccount.calls
#total_calls = #calls.list.count
However, I'm really struggling to figure out how to display unique calls (people sometimes call back form the same number and I only want to count calls from the same number once). I'm thinking this is a pretty simple method or two but I've burnt quite a few hours trying to figure it out (still a ruby noob).
Currently I've been working it in the console as follows:
#sub_account_client = Twilio::REST::Client.new(#account_sid, #auth_token)
#subaccount = #sub_account_client.account
#subaccount.calls.list({})each do |call|
#"from" returns the phone number that called
print call.from
end
This returns the following strings:
+13304833615+13304833615+13304833615+13304833615+13304567890+13304833615+13304833615+13304833615
There are only two unique numbers there so I'd like to be able to return '2' for this.
Calling class on that output shows strings. I've used "insert" to add a space then have done a split(" ") to turn them into arrays but the output is the following:
[+13304833615][+13304833615][+13304833615][+13304833615][+13304567890][+13304833615][+13304833615][+13304833615]
I can't call 'uniq' on that and I've tried to 'flatten' as well.
Please enlighten me! Thanks!
If what you have is a string that you want to manipulate the below works:
%{+13304833615+13304833615+13304833615+13304833615+13304567890+13304833615+13304833615+13304833615}.split("+").uniq.reject { |x| x.empty? }.count
=> 2
However this is more ideal:
#subaccount.calls.list({}).map(&:from).uniq.count
Can you build an array directly instead of converting it into a string first? Try something like this perhaps?
#calllist = []
#subaccount.calls.list({})each do |call|
#"from" returns the phone number that called
#calllist.push call.from
end
you should then be able to call uniq on #calllist to shorten it to the unique members.
Edit: What type of object is #subaccount.calls.list anyway?
uniq should work for creating a unique list of strings. I think you may be getting confused by other non-related things. You don't want .split, that's for turning a single string into an array of word strings (default splits by spaces). Which has turned each single number string, into an array containing only that number. You may also have been confused by performing your each call in the irb console, which will return the full array iterated on, even if your inner loop did the right thing. Try the following:
unique_numbers = #subaccount.calls.list({}).map {|call| call.from }.uniq
puts unique_numbers.inspect

Resources