diff --git a/arduino/arduino.ino b/arduino/arduino.ino index 24b2f34..5843903 100644 --- a/arduino/arduino.ino +++ b/arduino/arduino.ino @@ -1,10 +1,21 @@ #include #include #include -#include "state.h" #include "motor.h" #include "secrets.h" +#define INPUT_SIZE 4 + +enum state { + STATE_CONNECTING, + STATE_LOGGED_OUT, + STATE_LOGGED_IN, + STATE_INPUT_PASSCODE, +}; + +enum state current_state; +char input_code[INPUT_SIZE + 1]; + MKRIoTCarrier carrier; WiFiSSLClient wifi_client; MqttClient mqtt_client(wifi_client); @@ -15,6 +26,87 @@ int motor_count_max = 64; uint32_t green_led_color = carrier.leds.Color(0, 255, 0); +bool is_input_empty() +{ + for (int i = 0; i < INPUT_SIZE; i++) { + if (input_code[i]) return false; + } + return true; +} + +bool is_input_full() +{ + for (int i = 0; i < INPUT_SIZE; i++) { + if (!input_code[i]) return false; + } + return true; +} + +void change_state(enum state new_state) +{ + // Initialize state + switch (new_state) { + case STATE_INPUT_PASSCODE: + input_code[0] = '\0'; + input_code[1] = '\0'; + input_code[2] = '\0'; + input_code[3] = '\0'; + input_code[4] = '\0'; + break; + } + + current_state = new_state; + draw_state(); +} + +void draw_state() +{ + carrier.display.fillScreen(0x000); + + switch (current_state) { + case STATE_CONNECTING: + carrier.display.setCursor(20, 100); + carrier.display.setTextSize(3); + carrier.display.print("Connecting.."); + break; + + case STATE_LOGGED_OUT: + carrier.display.setCursor(15, 100); + carrier.display.setTextSize(2); + carrier.display.print("Press Green Button"); + carrier.leds.fill(green_led_color, 2, 1); + carrier.leds.setBrightness(5); + carrier.leds.show(); + break; + + case STATE_INPUT_PASSCODE: + if (is_input_empty()) { + carrier.display.setCursor(50, 100); + carrier.display.setTextSize(2); + carrier.display.print("Please enter"); + carrier.display.setCursor(80, 120); + carrier.display.print("passcode"); + } else { + carrier.display.setCursor(50, 100); + carrier.display.setTextSize(3); + for (int i = 0; i < INPUT_SIZE; i++) { + char ch = input_code[i]; + if (!ch) ch = '_'; + + carrier.display.print(ch); + carrier.display.print(' '); + } + } + break; + + case STATE_LOGGED_IN: + carrier.display.setCursor(40, 100); + carrier.display.setTextSize(3); + carrier.display.print("Logged in"); + break; + } +} + void setup() { Serial.begin(9600); @@ -54,6 +146,7 @@ void setup() carrier.Buzzer.beep(); mqtt_client.subscribe("dispense"); + mqtt_client.subscribe("login"); change_state(STATE_LOGGED_OUT); } @@ -71,16 +164,71 @@ void loop() // Receive MQTT messages int message_size = mqtt_client.parseMessage(); if (message_size) { + String topic = mqtt_client.messageTopic(); Serial.print("Got message with topic: "); - Serial.println(mqtt_client.messageTopic()); + Serial.println(topic); - if (mqtt_client.messageTopic() == "dispense") { + // Parse message + char *message = (char *)malloc(message_size + 1); + for (int i = 0; i < message_size && mqtt_client.available(); i++) { + message[i] = (char)mqtt_client.read(); + } + message[message_size] = '\0'; + + Serial.print("and payload: "); + Serial.println(message); + + // Check topic + if (topic == "dispense") { Serial.println("Dispensing..."); // Start rotating motor motor_count = motor_count_max; + } else if (topic == "login") { + Serial.println("Logged in"); + + int user_id; + if (sscanf(message, "%d", &user_id) > 0) { + change_state(STATE_LOGGED_IN); + } else { + change_state(STATE_INPUT_PASSCODE); + } } + + free(message); } - loop_state(); + switch (current_state) { + case STATE_LOGGED_OUT: + if (carrier.Buttons.onTouchDown(TOUCH2)) { + change_state(STATE_INPUT_PASSCODE); + } + break; + case STATE_INPUT_PASSCODE: + touchButtons buttons[] = { TOUCH0, TOUCH1, TOUCH3, TOUCH4 }; + char input_characters[] = "1234"; + + for (int i = 0; i < sizeof(buttons) / sizeof(buttons[0]); i++) { + if (carrier.Buttons.onTouchDown(buttons[i])) { + for (int j = 0; j < INPUT_SIZE; j++) { + if (!input_code[j]) { + input_code[j] = input_characters[i]; + break; + } + } + + if (is_input_full()) { + mqtt_client.beginMessage("login_request"); + mqtt_client.print(input_code); + mqtt_client.endMessage(); + } + + draw_state(); + + break; + } + } + + break; + } } diff --git a/arduino/state.h b/arduino/state.h deleted file mode 100644 index ba969f4..0000000 --- a/arduino/state.h +++ /dev/null @@ -1,9 +0,0 @@ -enum state { - STATE_CONNECTING, - STATE_LOGGED_OUT, - STATE_LOGGED_IN, - STATE_INPUT_PASSCODE, -}; - -void change_state(enum state new_state); -void loop_state(); \ No newline at end of file diff --git a/arduino/state.ino b/arduino/state.ino deleted file mode 100644 index 70bcf26..0000000 --- a/arduino/state.ino +++ /dev/null @@ -1,101 +0,0 @@ -#define INPUT_SIZE 4 - -enum state current_state; -char input_code[INPUT_SIZE]; - -bool is_input_empty() -{ - for (int i = 0; i < INPUT_SIZE; i++) { - if (input_code[i]) return false; - } - return true; -} - -void change_state(enum state new_state) -{ - // Initialize state - switch (new_state) { - case STATE_INPUT_PASSCODE: - input_code[0] = '\0'; - input_code[1] = '\0'; - input_code[2] = '\0'; - input_code[3] = '\0'; - break; - } - - current_state = new_state; - draw_state(); -} - -void draw_state() -{ - carrier.display.fillScreen(0x000); - - switch (current_state) { - case STATE_CONNECTING: - carrier.display.setCursor(20, 100); - carrier.display.setTextSize(3); - carrier.display.print("Connecting.."); - break; - - case STATE_LOGGED_OUT: - carrier.display.setCursor(15, 100); - carrier.display.setTextSize(2); - carrier.display.print("Press Green Button"); - carrier.leds.fill(green_led_color, 2, 1); - carrier.leds.setBrightness(5); - carrier.leds.show(); - break; - case STATE_INPUT_PASSCODE: - if (is_input_empty()) { - carrier.display.setCursor(50, 100); - carrier.display.setTextSize(2); - carrier.display.print("Please enter"); - carrier.display.setCursor(80, 120); - carrier.display.print("passcode"); - } else { - carrier.display.setCursor(50, 100); - carrier.display.setTextSize(3); - for (int i = 0; i < INPUT_SIZE; i++) { - char ch = input_code[i]; - if (!ch) ch = '_'; - - carrier.display.print(ch); - carrier.display.print(' '); - } - } - break; - } -} - -void loop_state() -{ - switch (current_state) { - case STATE_LOGGED_OUT: - if (carrier.Buttons.onTouchDown(TOUCH2)) { - change_state(STATE_INPUT_PASSCODE); - } - break; - case STATE_INPUT_PASSCODE: - touchButtons buttons[] = { TOUCH0, TOUCH1, TOUCH3, TOUCH4 }; - char input_characters[] = "1234"; - - for (int i = 0; i < sizeof(buttons) / sizeof(buttons[0]); i++) { - if (carrier.Buttons.onTouchDown(buttons[i])) { - - for (int j = 0; j < sizeof(input_code); j++) { - if (!input_code[j]) { - input_code[j] = input_characters[i]; - break; - } - } - - draw_state(); - - break; - } - } - - break; - }; -} \ No newline at end of file diff --git a/backend/Program.cs b/backend/Program.cs index 4bc5031..5cb1c55 100644 --- a/backend/Program.cs +++ b/backend/Program.cs @@ -49,9 +49,39 @@ var options = new MqttClientOptionsBuilder() await mqttClient.ConnectAsync(options, CancellationToken.None); -ApplicationState.MqttClient = mqttClient; +await mqttClient.SubscribeAsync( + new MqttFactory().CreateSubscribeOptionsBuilder().WithTopicFilter(f => f.WithTopic("login_request")).Build(), + CancellationToken.None +); + ApplicationState.DbContext = new DispenserContext(); +mqttClient.ApplicationMessageReceivedAsync += delegate(MqttApplicationMessageReceivedEventArgs args) { + var payload = System.Text.Encoding.Default.GetString(args.ApplicationMessage.PayloadSegment); + + switch (args.ApplicationMessage.Topic) { + case "login_request": + var user = ApplicationState.DbContext!.Users.FirstOrDefault(user => user.TouchCode == payload); + + var message = new MqttApplicationMessageBuilder() + .WithTopic("login"); + + if (user == null) { + message.WithPayload("error"); + } else { + message.WithPayload(user.Id.ToString()); + } + + mqttClient.PublishAsync(message.Build()); + + break; + } + + return Task.CompletedTask; +}; + +ApplicationState.MqttClient = mqttClient; + Console.WriteLine("Connected"); app.Run();