Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define Langauge For IFTTT #24

Open
cjackie opened this issue Feb 24, 2017 · 5 comments
Open

Define Langauge For IFTTT #24

cjackie opened this issue Feb 24, 2017 · 5 comments
Assignees

Comments

@cjackie
Copy link
Member

cjackie commented Feb 24, 2017

@kbumsik
Not sure if this is the right way to solve this problem. I will give my thought.

We need to define a simple language that can be interpreted by the remote server. Something like:

Condition

a statement that can evaluated into True or False
definition

Condition =>
     Operation Condition Condition |
     Operation Condition |
     DeviceValueName 'IS' DeviceValue

Operation => AND | OR | NOT

DeviceValueName => String
DeviceValue => String | Number

Action

a statement that can have effects on IoT devices

Action =>
    'SET' DeviceValueName DeviceValue

IFTTT Script

Script =>
  'IF' Condition 'THEN' Action

We have a user interface that will generate the script according to this definition, then we have a backend script engine that interpret and execute it.

For example, a script can be

IF AND relay IS 1 OR Led2 IS 0 Led1 IS 1 THEN SET Led3 0

And the backend script engine parses this, and execute it

@kbumsik
Copy link
Contributor

kbumsik commented Feb 25, 2017

Hmm I was just thinking to write structured JSON data to specify the operation. But this one sounds more interesting and make sense to me :) I think there should be a good reference designing this. Let me find one

@kbumsik
Copy link
Contributor

kbumsik commented Feb 26, 2017

I came up with a language design borrowing your idea. The format of below specification is based on EBNF.

Device = DeviceName'.'Property ;

Value = String | Number ;

Condition = 
    Device ('='|'>'|'<') Value ;

Action =
    'SET' Device '=' Value ;

IFTTTCommend =
    'IF' Condition {('OR'|'AND') Condition} 'THEN' {Action} 'END' ;

And the number of whitespace doesn't care. So we can write like the following as an example:

IF
    RPi_1.Button = "On"
    AND Gyro.x > 1.56
THEN
    SET RPi_1.Relay = 0
    SET RPi_2.Power = "Off"
END

What do you hink? BTW, lets start with a simpler way, supporting up to 2 conditions and only one action first.

@kbumsik kbumsik closed this as completed Feb 26, 2017
@kbumsik kbumsik reopened this Feb 26, 2017
@cjackie
Copy link
Member Author

cjackie commented Feb 26, 2017

how do you parse and interpret it?

@kbumsik
Copy link
Contributor

kbumsik commented Feb 26, 2017

Parsing? No problem!

Catch'em all Regex!!

import re

# Want explanation? Use https://regex101.com/ . This site will explain MUCH better than me :)
ifttt_re = re.compile(r'IF\s+([\w\W]*)\s+THEN\s+([\w\W]*)\s+END')
condition_1st_re = re.compile(r'(\w+)\.(\w+)\s+(\=|\>|\<)\s+(\"\w*\"|[-+]?\d*\.\d+|[-+]?\d+)')
condition_re = re.compile(r'(AND|OR)\s+(\w+)\.(\w+)\s+(\=|\>|\<)\s+(\"\w*\"|[-+]?\d*\.\d+|[-+]?\d+)')
action_re = re.compile(r'SET\s+(\w+)\.(\w+)\s+(\=|\>|\<)\s+(\"\w*\"|[-+]?\d*\.\d+|[-+]?\d+)')

script = '''IF
    RPi_1.Button = "On"
    AND Gyro.x > 1.56
THEN
    SET RPi_1.Relay = 0
    SET RPi_2.Power = "Off"
END'''

ifttt = ifttt_re.match(script)
print(ifttt)
if ifttt:
    # Capture condition and action
    condition_group = ifttt.group(1)
    action_group = ifttt.group(2)
    print("==== Condition START ====")
    # Get first condition
    condition_match = condition_1st_re.match(condition_group)
    print("First condtition")
    print("\tDevice: ", condition_match.group(1))
    print("\tProperty: ", condition_match.group(2))
    print("\tComparator: ", condition_match.group(3))
    print("\tValue: ", condition_match.group(4))
    i = 1

    # Capture the rest of conditions
    for matched in condition_re.finditer(condition_group):
        i += 1
        print(i, "th action")
        print("\tOperator: ", matched.group(1))
        print("\tDevice: ", matched.group(2))
        print("\tProperty: ", matched.group(3))
        print("\tComparator: ", matched.group(4))
        print("\tValue: ", matched.group(5))
    print("==== Condition END ====")
    # Capture all actions
    print("==== Action START ====")
    i = 0
    for matched in action_re.finditer(action_group):
        i += 1
        print(i, "th action")
        print("\tDevice: ", matched.group(1))
        print("\tProperty: ", matched.group(2))
        print("\tComparator: ", matched.group(3))
        print("\tValue: ", matched.group(4))
    print("==== Action END ====")

Result

==== Condition START ====
First condtition
	Device:  RPi_1
	Property:  Button
	Comparator:  =
	Value:  "On"
2 th action
	Operator:  AND
	Device:  Gyro
	Property:  x
	Comparator:  >
	Value:  1.56
==== Condition END ====
==== Action START ====
1 th action
	Device:  RPi_1
	Property:  Relay
	Comparator:  =
	Value:  0
2 th action
	Device:  RPi_2
	Property:  Power
	Comparator:  =
	Value:  "Off"
==== Action END ====

@kbumsik
Copy link
Contributor

kbumsik commented Feb 26, 2017

For execution, I need to think the design yet. But it is almost there. :P

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants