Extended script from above with all functionality and bug fixes. Except the domoticz part.
Code: Select all
#!/usr/bin/python
# -*- coding: utf8 -*-
import socket
import sys
import struct
import random
iBrewVersion = "White Tea Edition v0.06 © 2016 TRiXWooD"
#------------------------------------------------------
# iBrew DEFAULT USER SETTINGS
#
#------------------------------------------------------
#iKettle 2 or Smarter Coffee Host
host = '10.0.0.93';
#Domoticz Monitor
#format: "HOST:PORT" or "USERNAME:PASSWORD@HOST:PORT"
domoticz = "USERNAME:[email protected]:8090"
#------------------------------------------------------
# iBrew PROTOCOL
#
# Protocol information to iKettle 2.0 or Smarter Coffee
# Devices (500 lines of ugly code)
#------------------------------------------------------
#
# References:
# https://github.com/Jamstah/libsmarteram2/wiki/Protocol-documentation
# https://github.com/ian-kent/ikettle2/tree/master/protocol
# https://github.com/athombv/am.smarter/blob/master/node_modules/ikettle2.0/ikettle2.0.js
# https://github.com/athombv/am.smarter/blob/master/node_modules/coffee/index.js
# https://github.com/AdenForshaw/smarter-coffee-api/blob/master/smarter-coffee-api.py
# https://www.pentestpartners.com/blog/hacking-a-wi-fi-coffee-machine-part-1/
# https://www.hackster.io/lahorde/from-a-14-kettle-to-an-ikettle-d2b3f7
#
# https://github.com/nanab/smartercoffee/blob/master/sendcommand.py
#
#
class iBrewProtocol:
def base(self):
print
print "Smarter iKettle 2.0 & Smarter Coffee Protocol"
print "_____________________________________________"
print
print "Smarter uses a binary message protocol,"
print "either via UDP or TCP on port 2081"
print
print "Messages (commands and responses) use the syntax:"
print
print " <ID>[ARGUMENTS]<TAIL>"
print
print ""
print "The tail is always 7e or ~ in ASCII"
print
print "Arguments use this syntax:"
print
print " <ARGUMENT> is a single mandatory byte"
print " <[ARGUMENT]> is a single optional byte"
print " <ARGUMENT>{0,32} is mandatory, between 0 and 32 bytes"
print
print "Everything else, including spurious } characters, are ASCII literals"
print
print "Use messages command to list all messages"
print
def messages(self):
print
print "♨ ☕ ID Command Message Description"
print "____________________________________"
print " 02 Set the machine time"
print " 05 Set network SSID"
print " 07 Set WiFi password"
print "✕ 07 Start brewing Coffee???)"
print "♨ 0d Scan for WiFi networks"
print " 10 Reset ???"
print "♨ 15 Turn on"
print "♨ 16 Turn off"
print "♨ 20 Boiling Turn on"
print "♨ 21 Boiling Turn on"
print "♨ 22 Boiling Turn on"
print "♨ 23 Boiling Turn on ???"
print "♨ 28 ???"
print "♨ 2c Calibrate Water Sensor"
print " 32 ???"
print "✕ ☕ 35 Set strength of the coffee to brew"
print "✕ ☕ 36 Set number of cups to brew"
print "✕ ☕ 37 ???"
print "✕ ☕ 3c Toggle the Grinder on/off"
print "✕ ☕ 3e Turn on the hotplate"
print "✕ ☕ 40 Updating schedules ???"
print "✕ ☕ 41 Requesting schedules ???"
print "✕ ☕ 43 Schedules ???"
print "✕ ☕ 4a Turn off the hot plate"
print "♨ ☕ 64 Get Identify of device"
print "♨ 69 ???"
print "♨ 6a Get Firmware Info WiFi module"
print " 6d Firmware Update"
print
print "♨ ☕ ID Response Message Description"
print "___________________________________"
print "♨ ☕ 03 Status"
print " 0c Complete WiFi setup"
print "♨ 0e List of WiFi networks"
print "♨ 29 ???"
print "♨ 14 Device status"
print "♨ 2d Calibrate completed"
print "♨ ☕ 65 Identify of device"
print "♨ ☕ 6b Firmware Indo WiFi module"
print
print "Legend:"
print " ♨ iKettle 2"
print " ☕ Smarter Coffee"
print
def calibration(self):
print
print "Calibration:"
print
print " If the kettle is on the base during calibration, the numbers change to be higher,"
print " but the differences between levels seem the same. This means that the water level"
print " detection is probably weight based and that calibration is done at the base,"
print " which then remembers the weight for \'off base\'. To detect an empty kettle,"
print " the connecting device must account for the weight of the kettle itself."
def coffeebrewing(self):
print
print "Coffee Brewing:"
print
print " Between setting the number of cups, the strength of the coffee and start of brewing"
print " atleast 500ms is recommended."
def message(self,id):
print "________________________________________________"
if id == '02':
print "Message 02: Set Time"
print " ?"
print
print "Arguments: <Seconds><Minutes><Hours><Unknown><Day><Month><Century><Year>"
print "Note: Unknown is Day of week index?"
elif id == '03':
#Fix
print "d"
elif id == '05':
print "Message 05: Set network SSID"
print " ?"
print
print "Argument: <SSID>{0,32}"
print "Note: SSID is between 0 and 32 characters"
elif id == '07':
print "Message 07: Set WiFi password"
print " ?"
print
print "Argument: <password>{0,32}"
print "Note: password is between 0 and 32 characters"
print
print "Message 07: Start brewing Coffee???"
print " ?"
elif id == '0c':
print "Message 0c: WiFi setup finished"
print " ?"
print
print "No information available on message"
elif id == '0d':
print "Message 0d: Scan for WiFi networks"
print " ?"
print
print "Returns: Message 0e"
print
print "Example raw code: 0d 7e"
elif id == '0e':
print "Message 0e: List of WiFi network"
print " ?"
print
print "Arguments: <SSID>{0,32},-<db>{2}}"
print "Note: SSID is between 0 and 32 characters"
print " Sending message 0c without previous SSID/password messages will reset WiFi to factory settings"
print " -db is the signal strength in dBm format"
print
print "Examples: MyWifi,-56}"
print " MyWifi,-56}OtherWifi,-82}"
elif id == '10':
print "Message 10: Reset ???"
print " ?"
print
print "No information available on message"
elif id == '14':
print "Message 14: Device status"
print " ?"
print
print "Arguments: <status><temperature><waterHighbits><waterLowbits><unknown>"
self.calibration()
#FIX
# 1 0x00 Device Status. 0=Ready. 1=Boiling. 2=Keep warm. 3=Cycle finished. 4=Baby cooling.
# 2 0x28 Temperature in Celsius. 0x7f = Not on base.
# 3 0x07 Water level (high bits), see below.
# 4 0xf7 Water level (low bits), see below.
# 5 0x00 Unknown, possibly reserved. Only seen 0x00 on the iKettle 2.0
elif id == '15':
print "Message 15: Turn On"
print " ?"
print
print "Argument: <temperature>"
print
print "Example raw code: 15 ?? 7e"
elif id == '16':
print "Message 16: Turn Off"
print " ♨ iKettle 2.0"
print
print "Example raw code: 16 7e"
elif id == '20':
print "Message 20: Turn On"
print " ♨ iKettle 2.0"
print
print "Example raw code: 22 7e"
elif id == '21':
print "Message 21: Turn On"
print " ♨ iKettle 2.0"
print
print "Arguments: <[<temperature><[time]>]>"
print
print "Keep Warm between 5 and 20 minutes, 0 for normal on"
print
print "Example raw code: 21 7e"
print " 21 50 00 7e"
print " 21 30 05 7e"
print " 21 44 7e"
elif id == '22':
print "Message 22: Turn On"
print " ♨ iKettle 2.0"
print
print "Example raw code: 22 7e"
elif id == '23':
print "Message 23: Turn On"
print " ♨ iKettle 2.0"
print
print "Example raw code: 23 7e"
elif id == '28':
print "Message 28: ???"
print " ♨ iKettle 2.0"
print
print "No information available on message"
elif id == '29':
print "Message 29: Reply on 28???"
print " ♨ iKettle 2.0"
print
print "29 00 7e"
print "29 08 01 5f .. .. xx 7e"
print "29 01 01 5f 00 00 10 00 19 00 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7d 7e"
print
print "No information available on message"
elif id == '2c':
print "Message 2c: Calibrate Water Sensor"
print " ♨ iKettle 2 Only"
print
print "Example raw code: 2c 7e"
self.calibration()
elif id == '2d':
print "Message 2c: Calibrate finished"
print " ♨ iKettle 2 Only"
print
print "Arguments: <unkownArgument><unkownArgument>"
print
print "Example raw code: 2c ?? ?? 7e"
self.calibration()
elif id == '32':
print "Message 32: ???"
print " ?"
print
print "var brewing = new Buffer('3212130001117e', 'hex');"
print "var doneBrewing = new Buffer('3206130001117e', 'hex');"
elif id == '35':
print "Message 35: Set strength of the coffee to brew"
print " ☕ Smarter Coffee Only"
print
print "Argument: <strength>"
print
print "strength:"
print "00 Weak"
print "01 Medium"
print "02 Strong"
print
print "Example code: 35 01 7e"
self.coffeebrewing()
elif id == '36':
print "Message 36: Set number of cups to brew"
print " ☕ Smarter Coffee Only"
print
print "Argument: <numberOfCups>"
print "Note: numberOfCups must be between 1 and 12"
print
print "Example code: 36 03 7e"
self.coffeebrewing()
elif id == '37':
print "Message 37: ???"
print " ☕ Smarter Coffee Only"
print
print "No information available on message"
elif id == '3c':
print "Message 3c: Toggle the Grinder on/off"
print " ☕ Smarter Coffee Only"
print
print "Example raw code: 3c 7e"
elif id == '3e':
print "Message 3e: Turn on the hotplate"
print " ☕ Smarter Coffee Only"
print
print "Argument: <numberOfMinutes>"
print "Note: It is hardcoded in app with 5"
print " valid values are 0 to 30???"
print
print "unknownArgument:"
print "05 Default"
print
print "Example raw code: 3e 05 7e"
elif id == '40':
print "Message 40: Updating schedules ???"
print " ☕ Smarter Coffee Only"
print
print "No information available on message"
elif id == '41':
print "Message 41: Requesting schedules ???"
print " ☕ Smarter Coffee Only"
print
print "No information available on message"
elif id == '43':
print "Message 43: schedules ???"
print " ☕ Smarter Coffee Only"
print
print "No information available on message"
elif id == '4a':
print "Message 4a: Turn off the hotplate"
print " ☕ Smarter Coffee Only"
print
print "Example raw code: 4a 7e"
elif id == '64':
print "Message 64: Identify Device"
print " ♨ iKettle 2.0 & ☕ Smarter Coffee"
print
print "Note: Is used for auto discovery over UDP broadcast (after device setup is complete)"
print " This fails on some/most routers, which don't propagate UDP broadcasts"
print
print "Example raw code: 64 7e"
elif id == '65':
print "Message 65: Response Identify Device"
print " ♨ iKettle 2.0 & ☕ Smarter Coffee"
print
print "Arguments: <deviceType> <sdkVersion>"
print
print "deviceType:"
print "01 iKettle 2.0"
print "02 iSmarter Coffee"
print
print "sdkVersion:"
print "13 Firmware v19 (?)"
print
print "Example raw code: 65 01 13 7e"
elif id == 69:
print "Message 69: ???"
print " ♨ iKettle 2.0"
print
print "returns with 0 arguments 03 04 7e"
print "returns with 1 argument 03 00 7e"
elif id == '6a':
print "Message 6a: Get firmware version of WiFi module"
print " ♨ iKettle 2.0"
print
print "Example raw code: 6a 7e"
elif id == '6b':
print "Message 6b: Firmware version of WiFi module"
print " ♨ iKettle 2.0"
print
print "Note: iKettle 2.0 returns:"
print " AT+GMRAT version:0.40.0.0(Aug 8 2015 14:45:58)SDK version:1.3.0compile time:Aug 8 2015 17:19:38OK"
elif id == '6d':
print "Message 6d: Firmware Update"
print " ?"
print
print "Note: Disables wifi and creates a 'iKettle Update' network"
print " a hard device reset (hold power button for 10 seconds) required to fix"
print
print "Example raw code: 6d 7e"
else:
print 'No information available on message ID: ', id
print
def all(self):
self.base()
self.messages()
self.message("02")
self.message("03")
self.message("05")
self.message("07")
self.message("0c")
self.message("0d")
self.message("0e")
self.message("10")
self.message("13")
self.message("14")
self.message("15")
self.message("16")
self.message("20")
self.message("21")
self.message("22")
self.message("23")
self.message("28")
self.message("29")
self.message("2c")
self.message("2d")
self.message("32")
self.message("35")
self.message("36")
self.message("37")
self.message("3c")
self.message("3e")
self.message("40")
self.message("41")
self.message("43")
self.message("4a")
self.message("64")
self.message("65")
self.message("69")
self.message("6a")
self.message("6b")
self.message("6d")
#------------------------------------------------------
# iBrew CLIENT
#
# Client to iKettle 2.0 or Smarter Coffee Devices
#------------------------------------------------------
class iBrewClient:
port = 2081
command_off = '\x16'
command_on = '\x21'
command_info = '\x64'
# Coffee Commands (not tested)
command_grinder = '\x3c'
command_hotplate_off = '\x4a'
command_hotplate_on = '\x3e\x05'
command_number_of_cups = '\x36'
command_strength = '\x35'
# iKettle Commands
command_calibrate = '\x2c'
# Response messages
message_status = '\x03'
message_wifi_setup_finished = '\x0c'
message_wifi_list = '\x0e'
message_unknown = '\x29'
message_calibration_finished = '\x2d'
message_status_device = '\x14'
message_device_info = '\x65'
message_wifi_firmware = '\x6b'
tail = '\x7e'
offbase = '\x7f'
statusKettle = {
0x00 : "Ready",
0x01 : "Boiling",
0x02 : "Keep Warm",
0x03 : "Cycle Finished",
0x04 : "Baby Cooling",
}
statusCommand = {
0x00 : "Success",
0x01 : "Busy",
0x04 : "Failed",
0x05 : "No Carafe",
0x06 : "No Water",
0x69 : "Invalid Command",
0xff : "Unknown"
}
#------------------------------------------------------
# NETWORK CONNECTION: iKettle 2.0 & Smarter Coffee
#------------------------------------------------------
def connect(self, host):
try:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
print 'iBrew: Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
return False
try:
self.socket.connect((host, self.port))
except socket.error, msg:
print 'iBrew: Failed to connect to host (' + host + ') Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
self.log = False
self.read()
self.info()
self.host = host
def __init__(self,host, auto_connect = "True"):
if auto_connect:
self.connect(host)
def __del__(self):
self.socket.close()
#------------------------------------------------------
# NETWORK PROTOCOL: iKettle 2.0 & Smarter Coffee
#------------------------------------------------------
# read a protocol message
def read_message(self,socket):
try:
message = ""
i = 0
# let the buffer of the os handle this
data = self.socket.recv(1)
while data != self.tail:
message += data
data = self.socket.recv(1)
i += 1
message += data
return message
except socket.error, msg:
print 'iBrew: Failed to read message. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
# read a protocol message and decode it to internal variables
def read(self):
message = self.read_message(self.socket)
# Command Status
if message[0] == self.message_status:
self.status_command = struct.unpack('B',message[1])[0]
if not self.statusCommand.has_key(self.status_command):
self.status_command = 0xff
# Calibration
elif message[0] == self.message_calibration_finished:
self.calibration = struct.unpack('B',message[2])[0] + 256 * struct.unpack('B',message[1])[0]
# Device Status
elif message[0] == self.message_status_device:
#self.unknown = struct.unpack('B',message[5])[0]
self.status = struct.unpack('B',message[1])[0]
self.temperature = struct.unpack('B',message[2])[0]
self.waterlevel = struct.unpack('B',message[4])[0] + 256 * struct.unpack('B',message[3])[0]
if self.temperature == self.offbase:
self.onbase = False
else:
self.onbase = True
# Device Info
elif message[0] == self.message_device_info:
self.isSmarterCoffee = False
self.isKettle2 = False
if struct.unpack('B',message[1])[0] == 1:
self.isKettle2 = True
self.device = "iKettle 2.0"
if struct.unpack('B',message[1])[0] == 2:
self.isSmarterCoffee = True
self.device = "SmarterCoffee"
self.version = struct.unpack('B',message[2])[0]
if self.log:
self.print_message_received(message)
return message
# send a protocol message and wait's for response...
def send(self,message):
try:
if len(message) > 0 and message[len(message)-1] == self.tail:
self.socket.send(message)
if self.log:
self.print_message_send(message)
elif len(message) > 0:
self.socket.send(message+self.tail)
if self.log:
self.print_message_send(message+self.tail)
else:
return
except socket.error, msg:
print 'iBrew: Failed to send message. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
# keep reading until we got the response message
# if a message does not generate a response... we're in deep shit... FIX!
x = self.read()
while x[0] == self.message_status_device:
x = self.read()
return x
#------------------------------------------------------
# NETWORK CONVERTERS: iKettle 2.0 & Smarter Coffee
#------------------------------------------------------
# Convert raw data to hex string without 0x seperated by spaces
def message_to_string(self,message):
raw = ""
for x in range(0,len(message)):
y = struct.unpack('B',message[x])[0]
if y < 0x10:
raw += "0"
raw += hex(y)[2:4] + " "
return raw
# Convert hex string without 0x input maybe seperated by spaces or not
def string_to_message(self,code):
message = ""
if len(code) > 2 and code[2] != " ":
if len(code) % 2 == 0:
try:
message = code.decode("hex")
except:
print "iBrew: Invalid Input: Error encoding hex \'" + code + "\'"
else:
print "iBrew: Invalid Input: Missing character on position: " + str(len(code)+1)
elif len(code) % 3 == 2:
for x in range(0,(len(code) / 3)+1):
if x > 0:
if code[x*3-1] != ' ':
print "iBrew: Invalid Input: Expected space character on position: " + str(x*3)
break
s = code[x*3]+code[x*3+1]
try:
message += s.decode("hex")
except:
print "iBrew: Invalid Input: Error encoding hex \'" + s + "\' on position: " + str(x*3+1)
else:
print "iBrew: Invalid Input: Missing character on position: " + str(len(code)+1)
return message
#------------------------------------------------------
# CONVERTERS: iKettle 2.0
#------------------------------------------------------
def cups(self):
s = cups_string()
if s == "Empty" or s == "Not enough water":
return 0
if s == "Full":
return 7
return s[1]
# Fix Check value's
def cups_string(self):
if self.waterlevel < 850:
return "Empty"
elif self.waterlevel >= 850 and self.waterlevel < 1050:
return "Not enough water"
elif self.waterlevel >= 1050 and self.waterlevel < 1380:
return "1 Cups"
elif self.waterlevel >= 1400 and self.waterlevel < 1600:
return "2 Cups"
elif self.waterlevel >= 1600 and self.waterlevel < 1800:
return "3 Cups"
elif self.waterlevel >= 1800 and self.waterlevel < 2000:
return "4 Cups"
elif self.waterlevel >= 2000 and self.waterlevel < 2200:
return "5 Cups"
elif self.waterlevel >= 2200 and self.waterlevel < 2500:
return "6 Cups"
elif self.waterlevel >= 2500:
return "Full"
#------------------------------------------------------
# PRINT: iKettle 2.0 & Smarter Coffee
#------------------------------------------------------
def print_message_send(self,message):
print "iBrew: Message Send " + self.message_to_string(message)
if message[0] == self.command_grinder:
print " Toggle Grinder"
elif message[0] == self.command_hotplate_off:
print " Turn Hotplate On"
elif message[0] == self.command_hotplate_on:
print " Turn Hotplate Off"
elif message[0] == self.command_number_of_cups:
print " Set Number of Cups to Brew"
elif message[0] == self.command_strength:
print " Set Strength"
elif message[0] == self.command_on:
print " Turn On"
elif message[0] == self.command_off:
print " Turn Off"
elif message[0] == self.command_info:
print " Get Device Info"
elif message[0] == self.command_calibrate:
print " Calibrate Waterlevel"
else:
print " Unknown Command"
def print_message_received(self,message):
if message[0] != self.message_status_device:
print "iBrew: Message Received: " + self.message_to_string(message)
if message[0] == self.message_status:
print " Action Status: " + self.statusCommand[self.status_command]
elif message[0] == self.message_wifi_setup_finished :
print ' Wifi Not Implemented'
elif message[0] == self.message_wifi_list:
print ' Wifi Not Implemented'
elif message[0] == self.message_wifi_firmware:
print ' Wifi Firmware Not Implemented'
elif message[0] == self.message_unknown:
print ' Unknown Message Not Implemented'
elif message[0] == self.message_device_info:
print " Device Info: " + self.device + " Firmware v" + str(self.version)
elif message[0] == self.message_calibration_finished:
print " Calibration Base Value: " + str(self.calibration)
elif message[0] != self.message_status_device:
print " Unknown Reply Message"
def print_status(self):
print
if self.isKettle2 == True:
if self.onbase:
print 'Status ', self.statusKettle[self.status]
print 'Kettle On Base'
print 'Temperature ', self.temperature, 'ºC'
print 'Water level ', self.waterlevel, ' (', self.cups_string(), ')'
else:
print 'Status ', self.statusKettle[self.status]
print 'Kettle Not On Base'
if self.isSmarterCoffee == True:
print 'Status ', self.statusCoffee[self.status]
print
def print_short_status(self):
if self.isKettle2 == True:
if self.onbase:
print "iBrew: " + self.statusKettle[self.status] + " On Base (" + str(self.temperature) + "ºC, " + str(self.waterlevel) + " ["+ self.cups_string() + "])"
else:
print "iBrew: " + self.statusKettle[self.status] + " Not On Base"
if self.isSmarterCoffee == True:
print "iBrew: " + self.statusCoffee[self.status]
def print_connect_status(self):
print "iBrew: Connected to " + self.device + " Firmware v" + str(self.version) + " (" + self.host + ")"
#------------------------------------------------------
# COMMANDS: iKettle 2.0 & Smarter Coffee
#------------------------------------------------------
def info(self):
self.send(self.command_info)
#------------------------------------------------------
# COMMANDS: iKettle 2.0
#------------------------------------------------------
def calibrate(self):
self.send(self.command_calibrate)
def off(self):
self.send(self.command_off)
def on(self):
self.send(self.command_on)
#------------------------------------------------------
# COMMANDS: Smarter Coffee
#------------------------------------------------------
def hotplate_off(self):
if self.isSmarterCoffee == True:
self.send(self.command_hotplate_off)
else:
print 'iBrew: The device does not have a hotplate'
def hotplate_on(self):
if self.isSmarterCoffee == True:
self.send(self.command_hotplate_on)
print 'iBrew: The device does not have a hotplate'
def grinder(self):
if self.isSmarterCoffee == True:
self.send(self.command_grinder)
else:
print 'iBrew: The device does not have a grinder'
def number_of_cups(self,number):
if self.isSmarterCoffee == True:
if number < 1 or number > 12:
print 'iBrew: Invalid Number of Cups: ',number
self.send(self.command_grinder+str(number))
else:
print 'iBrew: The device does not let you choose the number of cups to brew'
def coffee_strength(self,strength):
if self.isSmarterCoffee == True:
if strength == "weak":
number = 0
elif strength == "medium":
number = 1
elif strength == "strong":
number = 2
else:
print 'iBrew: Invalid Strength: ',strength
if number:
self.send(self.command_strength+str(number))
else:
print 'iBrew: The device does not let you choose the coffee strength'
def raw(self,code):
self.send(self.string_to_message(code))
#------------------------------------------------------
# iBrew CONSOLE
#
# Console for iKettle 2.0 or Smarter Coffee Devices
#
# Note that the device status is the only message not
# printed in raw format...
#------------------------------------------------------
class iBrewConsole:
def introduction(self):
print
print "For list of commands type: help and press enter"
print "Press enter for status update and press ctrl-c to quit"
print
def help(self):
print
print " [data] Send raw data to device"
print " cups [nr] ☕ Set number of cups"
print " calibrate ♨ Calibrates Waterlevel"
print " examples Show examples of commands"
print " grinder ☕ Toggle grinder"
print " help This help"
print " hotplate off ☕ Turn hotplate off"
print " hotplate on ☕ Turn hotplate on"
print " info Device info"
print " messages List all protocol messages"
print " message [id] List protocol messages detail"
print " off Turn off"
print " on Turn on"
print " protocol Print protocol structure"
print " quit Quit console"
print " status Show status"
print " strength [s] ☕ Set strength coffee (weak, medium or strong)"
print
print " ☕ Smarter Coffee Only"
print " ♨ iKettle 2.0 Only"
print
def examples(self):
print
print "Example:"
print " off iKettle 2.0 Stop boiling"
print " messages Show all protocol messages"
print " message 3e Show protocol message 3a, turn hotplate on"
print " 167E Send iKettle 2.0 raw off"
print " 21 30 05 7e Send iKettle 2.0 raw on"
print " strength weak Set SmarterCoffee coffee strength to weak"
print " cups 3 Set SmarterCoffee number of cups to brew"
print
def joke(self):
teajokes = [["What do you call a talkative drink?","Chai tea."],
["How long does it take to brew Chinese tea?","Oolong time."],
["When shouldn't you drink a hot beverage?","If it's not your cup of tea."],
["How does Moses make his tea?","Hebrews it."],
["What drink do goalies hate?","Penal-tea."],
["How do you ask a dinosaur to lunch?","Tea Rex?"],
["What does a worry wart drink?","Safe-Tea."],
["Why did the hipster burn his tongue?","Because he drank his tea before it was cool."],
["What drink brings you down to earth?","Gravi-Tea."],
["What do sophisticated fish drink?","Salt-Tea."],
["Why did the tea bag have to do it's laundry?","Because it was stained."],
["What kind of music do teapots like?","Jasmine."],
["Why must you be careful of tea at night?","Because it might mug you."],
["What does a tea bag do when it's tired?","It seeps."],
["Why did the teapot get in trouble?","Because he was naughtea."],
["What did the teapot wear to bed?","A nightea"],
["What happens when an old teapot laughs too hard?","It teas its pants."],
["It is time to get this par tea started!","Right?"],
["Hello Brew-TEA-Full!!!","Your kettle"],
["I love to drink tea each day","It brings out my inner tranquili-Tea"],
["Today!","Full of creativi-Tea"],
["It tends to break the ice very easily","Flirt-Tea."],
["When your kettle is too","Chat-Tea"],
["Where there is tea","There is hope!"],
["If tea is the drink of love","Then brew on!"],
["It really is a serious problem","If tea can’t fix it."],
]
coffeejokes = [["Why are men are like coffee?"," The best ones are rich, hot, and can keep you up all night!"],
["Why is a bad cup of coffee the end of a marriage?","Because it's GROUNDS for divorce!"],
["What do you call sad coffee?","Despresso"],
["Did you know it's a sin for a woman to make coffee?","In the bible it says He-brews"],
["Why Coffee is better than a Woman?","Coffee goes down easier!"],
["They call me \"coffee\"","Cause I grind so fine."],
["Hold the sugar please","You're sweet enough for the both of us"],
["So I've Been thinking about you a latte","Your coffee grinder"],
["How do you look so good before coffee?","Your coffee machine"],
]
joke = random.choice(teajokes+coffeejokes)
print "\n \'" + joke[0] + "\'\n -- " + joke[1] + "\n"
def __init__(self,host):
client = iBrewClient(host)
client.print_connect_status()
client.print_status()
self.joke()
client.log = True
self.introduction()
cursor = client.host + ":" + client.device + "$"
lastreply = ""
while True:
try:
input = raw_input(cursor).lower()
if input == "on":
client.on()
elif input == "off":
client.off()
elif input == "hotplate on":
client.hotplate_on()
elif input == "hotplate off":
client.hotplate_off()
elif input == "grinder":
client.grinder()
elif input[0:9] == "strength ":
if input[9:14] == "weak":
client.coffee_strength("weak")
if input[9:16] == "strong":
client.coffee_strength("strong")
if input[9:16] == "medium":
client.coffee_strength("medium")
elif input[0:5] == "cups ":
# FIX THIS
client.cups(3)
elif input == "exit" or input =="quit":
sys.exit()
elif input == "joke":
print
self.joke()
print
elif input == "help":
self.help()
elif input == "info":
client.info()
elif input == "calibrate":
client.calibrate()
elif input == "examples":
self.examples()
elif input == "protocol":
iBrewProtocol().base()
elif input == "messages":
iBrewProtocol().messages()
elif input[0:8] == "message ":
iBrewProtocol().message(input[8:11])
elif len(input) > 0 and input != "status":
client.send(client.string_to_message(str(input)))
client.read()
if input == "status":
client.print_status()
else:
client.print_short_status()
except:
print
break
#------------------------------------------------------
# iBrew MONITOR
#
# Monitors iKettle 2.0 or Smarter Coffee Devices
#------------------------------------------------------
class iBrewMonitor:
def __init__(self,host):
client = iBrewClient(host)
client.print_connect_status()
print "iBrew: Press ctrl-c to quit"
lastreply = ""
while True:
try:
reply = client.read()
if lastreply == reply:
pass
else:
lastreply = reply
client.print_short_status()
except:
print
break;
#------------------------------------------------------
# iBrew DOMOTICZ BRIDGE
#
# Bridges the gap between Domoticz and iKettle 2.0 or
# Smarter Coffee Devices
#------------------------------------------------------
class iBrewDomoticzBridge:
def __init__(self,host):
client = iBrewClient(host)
client.print_connect_status()
print "iBrew: Press ctrl-c to quit"
lastreply = ""
while True:
try:
reply = client.read()
if lastreply == reply:
pass
else:
lastreply = reply
# PUT CODE DOMOTIZ HERE
client.print_short_status()
except:
print
break;
#------------------------------------------------------
# iBrew EMULATES
#
# Emulates iKettle 2.0 or a Smarter Coffee Device
#------------------------------------------------------
"""
def server(self,type):
print "iBrew: Not Implemented"
def emulate(self,type):
print "iBrew: Not Implemented"
def relay(self):
print "iBrew: Not Implemented"
"""
#------------------------------------------------------
# iBrew COMMAND LINE
#
# Command line access for iKettle 2.0 or Smarter Coffee
# Device
#------------------------------------------------------
class iBrewCommandLine:
def help(self):
print "iBrew ☕ Smarter Coffee & ♨ iKettle 2.0 Control"
print iBrewVersion
print
print 'Usage:'
print ' iBrew.py [option] (host)'
print
print '[options]'
print ' console'
print ' cups [number]'
print ' domoticz [options] (connect)'
print ' emulate [kettle, coffee]'
print ' grinder'
print ' hotplate off'
print ' hotplate on'
print ' monitor'
print ' off'
print ' on'
print ' protocol'
print ' raw [data]'
print ' relay'
print ' status'
print ' strength [weak, medium or strong]'
print
def __init__(self,host):
# Lower Case Arguments
arguments = len(sys.argv) - 1
if arguments >= 1:
arg1 = sys.argv[1].lower()
if arguments >= 2:
arg2 = sys.argv[2].lower()
if arguments >= 3:
arg3 = sys.argv[3].lower()
# No arguments display help
if arguments == 0:
self.help()
sys.exit()
# Set the device host if in arguments
if arguments == 4:
host = arg3
elif arguments == 3:
host = arg2
# Preform action!
if arguments >= 1:
if arg1 == "on":
iBrewClient(host).on()
elif arg1 == "off":
iBrewClient(host).off()
elif arg1 == "status":
iBrewClient(host).print_status()
elif arg1 == "grinder":
iBrewClient(host).grinder()
elif arg1 == "protocol":
iBrewProtocol().all()
elif arg1 == "monitor":
iBrewMonitor(host)
elif arg1 == "console":
iBrewConsole(host)
elif arg1 == "relay":
iBrewServer(host).relay()
elif arg1 == "domoticz":
iBrewDomoticzBridge(host)
elif arguments >= 2:
if arg1 == "raw":
iBrewClient(host).raw(arg2)
elif arg1 == "hotplate" and arg2 == "on":
iBrewClient(host).hotplate_on()
elif arg1 == "hotplate" and arg2 == "off":
iBrewClient(host).hotplate_off()
elif arg1 == "strength":
iBrewClient(host).coffee_strength(arg2)
elif arg1 == "cups":
# FIX WRONG IP{UT
iBrewClient(host).number_of_cups(arg2)
elif arg1 == "emulate" and arg2 == "kettle":
iBrewClient(host,False).emulate("kettle")
elif arg1 == "emulate" and arg2== "coffee":
iBrewClient(host,False).emulate("coffee")
else:
self.help()
print 'iBrew: Invalid option: ',arg1
print
else:
self.help()
print 'iBrew: Invalid option: ',arg1
print
#------------------------------------------------------
# MAIN
#
# Start any program you like default is command line
#------------------------------------------------------
iBrewCommandLine(host)
#iBrewMonitor(host)
#iBrewConsole(host)