-
1Snap Glove Electrical
The Snap glove is rather straightforward with the esp32. I hooked it up to a single cell lipo for power. Gpio 14 is a capacitive touch pin, called T6 when coding. I attached a wire to gpio 14 and soldered it to silver conductive thread!
*Remember to keep your touch pads small so they have good sensitive control. Too large of a pad will result in no touch triggers or constant touch depending on how the sensitivity is set.
-
2Soldering The Conductive Fabric
Conductive Fabric is definitely difficult to solder (if you are me). I find that getting your iron just hot enough to melt your solder and nothing beyond that is where you want to stay.
Tin your wire by melting some solder onto it, place it on the conductive fabric, and apply heat from with your soldering iron in burst of 3 seconds. Check the solder joint after each burst to see if more heat needs to be applied or if it will work.
Just take it slow, and don't be afraid to mess this step up.
-
3Stitch the Fabric onto the Glove
I stitched all the sensor pads in with regular thread, and sewed some of the cabling as well. This helps with repeated bending of the solder joint.
The sensor that is closest to your thumb is where your middle finger ends, while snapping. -
4Python Code IRC Twitch Bot!
The files for this code is hosted in the files section of this project.
Lets just start by importing the Socket, time, random, and math libraries.
import cfg import socket import time import random import math
They cfg file is one custom made with your username, password, and channel name for the bot you are putting into a twitch channel.
Now let's define how our timeout command will function.
def timeout(sock, user, secs): """ Time out a user for a set period of time. Keyword arguments: sock -- the socket over which to send the timeout command user -- the user to be timed out secs -- the length of the timeout in seconds (default 600) """ chat(sock, "/timeout {}".format(user, secs)) def untimeout(sock,user): chat(sock,"/unban {}".format(user))
When you call this function, you'll need to call out which socket you are trying to communicate with, the username you are timing out, and how long they will be banned for.
I also included an undo timeout command utilizing Twitch's unban function.
s = socket.socket() s.connect((cfg.HOST,cfg.PORT)) s.send("PASS {}\r\n".format(cfg.PASS).encode("utf-8")) s.send("NICK {}\r\n".format(cfg.NICK).encode("utf-8")) s.send("JOIN {}\r\n".format(cfg.CHAN).encode("utf-8")) CHAT_MSG=re.compile(r"^:\w+!\w+@\w+.tmi.twitch.tv PRIVMSG #\w+ :")
This section of code creates the socket, and passes information sorted in the cfg file I mentioned earlier. It also creates a compiler/decompiler for twitch messages.
Let's create some variables to store the usernames and even a chat counter for each person.
vips = [] vrem = [] vipc = [] vipCount = 0
Now Let's create an infinite loop to run through, and wait for a message from twitch (chat). We then are going to check if it is a ping. A pong will need to be sent if our bot is to remain connected to Twitch.
while True: response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) print('sent')
But what if it isn't a ping, but an actual chat we want to pay attention to? We will separate the message and username out of the info we received.
else: username = re.search(r"\w+", response).group(0) # return the entire match message = CHAT_MSG.sub("", response) # s.send(s,username +" + " + message) print(username + ": " + message)
With this information we are going to start collecting everyone in chat, put them into a list, and count how many times they speak in chat.
if username in vips: # will need to edit out tvheadbot, atltvhead, tmi from the messages collected! before doing the thanos glove # if its tvhead bot do nothing ind = vips.index(username) vipCount = vipc[ind] vipCount = vipCount + 1 vipc[ind] = vipCount print(vips) print(vipc) # print(username + " has spoken " + str(vipCount) + " times.") else: vips.append(username) vipc.append(1)
If the username is not in the list VIPS, it will add them to it. It also adds a integer into another list to count their interactions. If the user is in the list, it will add to their integer.
Next lets see if the message is our SNAP command. The Snap command will create a new list for those who will be timed out at random, without repeating. This new list is calculated to be half of all of those that spoke in chat, rounded up. It also accounts for the twitch entity in all chats tmi, and your chatbot. in my case tvheadbot.
if message.strip() == "SNAP" and username == "tvheadbot": # these operations move half of the chat to a new list for removal oglength = len(vips) delenght = math.ceil((oglength-3)/2) while len(vrem) < delenght: userToMove = random.choice(vips) if userToMove == "tmi" or userToMove == "tvheadbot" or userToMove == "atltvhead": # do nothing print("Encountered either Tmi or tvheadbot or atltvhead") else: if userToMove in vrem: print("User " + userToMove + " is already to be timed out.") else: vrem.append(userToMove)
Once we have sorted half of the chat into a the removal list. it is time to time them out.
# this is where I do the timeout for q in vrem: # print(q) timeout(s, q, 10) time.sleep(1 / cfg.RATE) # remember to wipe out vrem I want to unban / untimout time.sleep(1 / cfg.RATE)
Keeping everyone in a list will allow you to unban them with a snap as well!
Some things that your chatbot cannot do is timeout moderators and set your chat into emote only mod. I wish I could enable emote only mode, but I'll have to make it with the streamers username.
-
5Arduino ESP32 Code
I am using an older version of IRCClient which I modified to work with Twitch. If you use the most up to date version, it will work with Twitch out of the box.
The first thing to add are the libraries, defining our wifi network, and information to pass to twitch.
#include <WiFi.h> #include <IRCClient.h> /*-----------------------------------------------------------------------------------*/ #define ssid1 "Wifi" #define password1 "Password" #define IRC_SERVER "irc.chat.twitch.tv" #define IRC_PORT 6667 #define IRC_NICK "Bot_Name" #define IRC_CHAN "#Channel_Name" #define IRC_PASS "oauth:####" WiFiClient wiFiClient; IRCClient client(IRC_SERVER, IRC_PORT, wiFiClient);
We call out our wificlient, and our ircclients here with the proper twitch ports listed. your bot, channel name, and password are all things you will need change.
Let's define some variables that will help us not time people out when we don't want to.
boolean snapboo = false; boolean emoteboo = false;
This next section of code is for the touch sensors built into the esp 32. We are also creating a function that will be called for the snap is triggered.
int thresholdTwo = 60; bool touch2detected = false; byte touchCountTwo = 0; unsigned long touchTimeTwo; unsigned long oldTouchTimeTwo; void gotTouch2(){ //figure out calibration here! //get time and incriment timer touchTimeTwo = millis(); touchCountTwo++; // if counter is above a certain # in a certain timeout decrease sensitivity (time is going to be half second) if(touchCountTwo >=3 && (touchTimeTwo-oldTouchTimeTwo)<=400 && thresholdTwo > 20){ thresholdTwo=thresholdTwo-1; // reset count touchCountTwo=0; } // if counter is below a # and a certain timeout increase sensitivity (time is going to be 2 min?) else if((touchTimeTwo-oldTouchTimeTwo)>=60000){ // touchCount<1 && probably doesn't need the <1 touch count. if it creates too sensitive of a sensor, it will be backed off imediatly after. it should jut create more triggers after the high five thresholdTwo++; // reset counter touchCountTwo=0; } // if counter is below # and timer is between sensitivity triggers touch detected else if(400<(touchTimeTwo-oldTouchTimeTwo) && (touchTimeTwo-oldTouchTimeTwo)<60000){ touch2detected = true; delay(500); // reset counter } // time saved to new variable and reset oldTouchTimeTwo = touchTimeTwo; }
Every time a snap is triggered, it will calibrate the sensor, checking that it is a real touch by comparison of time intervals and number of triggers.
Next lets create our setup loop and attach our interrupts. The wifi and clients will also begin.
void setup() { WiFi.begin(ssid1, password1); client.setCallback(callback); client.setSentCallback(debugSentCallback); touchAttachInterrupt(T7,gotTouch2,thresholdTwo); }
Now, in our main loop, we are going to pass our information to twitch, and keep passing it until we are connected.
void loop() { // put your main code here, to run repeatedly: if (!client.connected()) { //Serial.println("Attempting IRC connection..."); // Attempt to connect if (client.connect(IRC_NICK, IRC_CHAN, IRC_PASS)) { //Serial.println("connected"); client.sendMessage(IRC_CHAN, "Hello everyone! I'm TvheadBot, a construct, assistant within the head of Atltvhead. If you have any questions type !help , and I'll post a link to all the channel commands. Let's Tune into Good Vibes! <3"); } else { //Serial.println("failed... try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } return; }
We will call our callback function which checks for the twitch messages and breaks it down into the ping/pong interaction, chat message, and username. We will also start checking to see if a snap was detected and seeing if any of our keys have been unlocked.
client.loop(); //Time Outs or Emote Only if(touch2detected){ touch2detected = false; if(snapboo){ snapboo = false; client.sendMessage(IRC_CHAN,"SNAP"); } else if(emoteboo){ emoteboo = false; client.sendMessage(IRC_CHAN,"IT'S EMOTE TIME!"); } else{ client.sendMessage(IRC_CHAN,"High Five Mode Initiated"); } } }
Unfortunately emote only mode cannot be triggered by a chat bot, so sad.
These commands are recognized by our python script to initiate the timeouts.
Mentioned above, we breakdown the twitch messages, for ping/pong, username, message.
if a particular word is written by a particular username (username) then unlock either the snap, or emote only mode (which again I am dumb and a chatbot cannot trigger).
void callback(IRCMessage ircMessage) { //Serial.println("In CallBack"); // PRIVMSG ignoring CTCP messages if (ircMessage.command == "PRIVMSG" && ircMessage.text[0] != '\001') { //Serial.println("Passed private message."); String message("<" + ircMessage.nick + "> " + ircMessage.text); if(ircMessage.text == "sk" && ircMessage.nick == "username"){ snapboo = true; client.sendMessage(IRC_CHAN,"The Snap has been unlocked!"); } else if(ircMessage.text == "ek" && ircMessage.nick == "username"){ emoteboo = true; client.sendMessage(IRC_CHAN,"Emote only ready!"); } return; } }
Lastly, just setup a debug for the clients.
void debugSentCallback(String data) { //Serial.println("I am in debug"); Serial.println(data); }
-
6Enjoy those Snaps (oh and cut a hole for the sensor to work)
How off your build and Snap your chat!
Don't forget to cut a hole so that your finger can contact the sensor!
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.