esp8266 websockets type == WStype_TEXT is always false even thou im sending data - websocket

I am trying to serve a webpage that has a color wheel. When the user changes the color on the wheel I want to send the new rgb value to the esp but the code on the esp never enters
if(type == WStype_TEXT)
Backend (esp8266 code):
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <WebSocketsServer.h>
#include "index.h"
const char* WiFissid = "ssid";
const char* WiFiPassword = "password";
const int WebServerPort = port;
const int WebSocketsPort = port;
ESP8266WebServer WebServer(WebServerPort);
WebSocketsServer WebSockets = WebSocketsServer(WebSocketsPort);
const int RedPin = 13;
const int GreenPin = 12;
const int BluePin = 14;
const int Resolution = 256;
int RedValue = 0;
int GreenValue = 0;
int BlueValue = 255;
/* Serve Web Page */
void ServeMainPage()
{
WebServer.send(200, "text/html", MainPage);
}
/* Web Sockets Get Input */
void WebSocketsGetData(uint8_t num, WStype_t type, uint8_t * payload, size_t length)
{
if(type == WStype_CONNECTED)
{
IPAddress ip = WebSockets.remoteIP(num);
Serial.println(String(ip[0]) + String(ip[1]) + String(ip[2]) + String(ip[3]));
String _payload = String((char *) &payload[0]);
Serial.println(_payload);
}
else if(type == WStype_TEXT)
{
String _payload = String((char *) &payload[0]);
Serial.println(_payload);
}
else if(type == WStype_DISCONNECTED)
{
Serial.println("Client disconnected");
}
}
/* Setup */
void setup()
{
/* Map Pins and Set Default Color */
analogWriteRange(Resolution);
analogWrite(RedPin, RedValue);
analogWrite(GreenPin, GreenValue);
analogWrite(BluePin, BlueValue);
/* Start Serial */
Serial.begin(9600);
/* Connect to WiFi */
WiFi.mode(WIFI_STA);
WiFi.begin(WiFissid, WiFiPassword);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
}
Serial.println(WiFi.localIP());
/* Start and Config Web Server */
WebServer.on("/", ServeMainPage);
WebServer.begin();
/* Start and Config Web Sockets Server */
WebSockets.onEvent(WebSocketsGetData);
WebSockets.begin();
}
void loop()
{
WebServer.handleClient();
WebSockets.loop();
}
index.h:
const char MainPage[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<meta name = "viewport" content = "width=device-width, initial-scale=1">
<meta charset="UTF-8">
<link rel = "stylesheet" href = "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js"></script>
<script src = "https://cdn.jsdelivr.net/npm/#jaames/iro"></script>
<title>Leduri Rares</title>
</head>
<body>
<div class = "container-fluid">
<div class = "row">
<div class = "wheel" id = "ColorWheel"></div>
</div>
</div>
</body>
</html>
<style>
body
{
background-color: #000000;
overflow-x: hidden;
}
h1
{
color: white;
}
.container-fluid
{
margin-top: 5%;
}
.row
{
text-align: center;
}
#ColorWheel
{
margin: 0 auto;
}
#media only screen and (max-width: 800px)
{
.container-fluid
{
margin-top: 10%;
}
#ColorWheel
{
margin: 5% auto;
}
}
</style>
<script>
let Socket = new WebSocket("wss://myIP:WSPort");
Socket.onclose = function(event)
{
if (event.wasClean)
{
alert("Connection with the server was closed smoothly");
} else
{
alert("Connection with the server was closed unexpectedly");
}
};
Socket.onerror = function(error)
{
alert("Connection Error: " + String(error.message));
};
var colorWheel = new iro.ColorPicker("#ColorWheel",
{
color: "rgb(255, 255, 255)",
borderWidth: 2,
borderColor: '#ffffff',
width: 275,
});
colorWheel.on('color:change', function(color, changes)
{
var Color = colorWheel.color.rgb;
let ColorsJSON = {
Red: Color.r,
Green: Color.g,
Blue: Color.b
};
Socket.send(JSON.stringify(ColorsJSON));
});
</script>
)=====";
I an new to programming and I have no idee why this is not working, any help is appreciated!

Your ESP8266 skecth is OK. Just tested with my own client.
Double check your index.h or replace it by a simple one for testing purpose.

Related

ESP32 WebServer performance for 72xWS2812 RGB status

Webserver network timing
Why AJAX is so laggy?
The most take a time: Initial connection.
How to speed up refreshing status of 72 rgb led?
I try to reach 100Hz.
Why AJAX is so laggy?
The most take a time: Initial connection.
How to speed up refreshing status of 72 rgb led?
I try to reach 100Hz.
Why AJAX is so laggy?
The most take a time: Initial connection.
How to speed up refreshing status of 72 rgb led?
I try to reach 100Hz.
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
const char* ssid = "ssid";
const char* password = "password";
WebServer server(80);
bool refresh = true;
void handleRoot() {
String html = "<html><head><style>.led-box {width: 10px; height: 10px; border: 1px solid black; float: left; margin-right: 1px;}</style>";
html += "<script>";
html += "function updateLEDs() {";
html += " var xhr = new XMLHttpRequest();";
html += " xhr.open('GET', '/updateLEDs', true);";
html += " xhr.onreadystatechange = function() {";
html += " if (xhr.readyState == XMLHttpRequest.DONE) {";
html += " var colors = xhr.responseText.split(',');";
for (int i = 1; i <= 72; i++) {
html += " document.getElementById('led" + String(i) + "').style.backgroundColor = '#' + colors[" + String(i - 1) + "];";
}
html += " }";
html += " };";
html += " xhr.send();";
html += "}";
html += "setInterval(updateLEDs, 1000);";
html += "</script></head><body>";
for (int i = 1; i <= 72; i++) {
html += "<div id='led" + String(i) + "' class='led-box'></div>";
}
html += "</body></html>";
server.send(200, "text/html", html);
}
void handleUpdateLEDs() {
String colorCodes = "";
for (int i = 1; i <= 72; i++) {
if (i > 1) colorCodes += ",";
colorCodes += String(random(0xFFFFFF), HEX);
}
server.send(200, "text/plain", colorCodes);
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
server.on("/", handleRoot);
server.on("/updateLEDs", handleUpdateLEDs);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
}
The ESP32 is a fairly sluggish little microcontroller to begin with, and you give it lots of unnecessary string processing to do on each HTTP request.
The worst bottleneck is your handleRoot() function - it dynamically assembles the exact same HTML document for every request. You do several hundreds of String concatenations every time someone GETs the root document. That's going to be slow. Pre-assemble the string (e.g. using raw string literals in setup()), only return the value in handleRoot().
String rootHtml;
void handleRoot() {
server.send(200, "text/html", rootHtml);
}
void setup() {
rootHtml = R"MYRAW(
<html><head><style>.led-box {width: 10px; height: 10px; border: 1px solid black; float: left; margin-right: 1px;}</style>
<script>
function updateLEDs() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/updateLEDs', true);
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
var colors = xhr.responseText.split(',');
)MYRAW";
for (int i = 1; i <= 72; i++) {
rootHtml += " document.getElementById('led" + String(i) + "').style.backgroundColor = '#' + colors[" + String(i - 1) + "];";
}
// ... etc
}
The handleUpdateLEDs() function also does at least 144 string concatenations, which is probably not the fastest algorithm for assembling a large string. I'd experiment with snprintf() and friends.
Note that the Arduino WebServer class is not built for speed, it's built for simplicity. Experiment with ESP IDF HTTP server to get better performance.

Electric UI example ESP32 websockets example code issue

This is the example code given for Electric UI's ESP32 websockets intergration.
// This example was written with the ESP8266 and ESP32 as the target hardware.
// Connects to a wifi access point and runs a websockets server as a transport for eUI.
// The ws path is hinted to the UI over the serial connection which ruggedises connection discovery.
// Base wifi libraries from the ESP library pack
#include "WiFi.h"
#include "WiFiMulti.h"
#include "WiFiClientSecure.h"
// Websockets library https://github.com/Links2004/arduinoWebSockets
#include "WebSocketsServer.h"
#include "electricui.h"
#define LED_PIN LED_BUILTIN
// Define default network credentials
char * wifi_ssid = "ssid";
char * wifi_pass = "password";
uint8_t ws_connected = 0; //state indication
uint8_t ws_port = 80;
char ws_path[] = "ws(s)://255.255.255.255:81";
// Simple variables to modify the LED behaviour
uint8_t blink_enable = 1; //if the blinker should be running
uint8_t led_state = 0; //track if the LED is illuminated
uint16_t glow_time = 200; //in milliseconds
// Keep track of when the light turns on or off
uint32_t led_timer = 0;
//example variables
uint8_t example_uint8 = 21;
uint16_t example_uint16 = 321;
uint32_t example_uint32 = 654321;
float example_float = 3.141592;
char demo_string[] = "ESP32 Test Board";
eui_message_t dev_msg_store[] = {
EUI_UINT8( "wsc", ws_connected),
EUI_CHAR_ARRAY( "ws", ws_path ),
EUI_UINT8( "led_blink", blink_enable ),
EUI_UINT8( "led_state", led_state ),
EUI_UINT16( "lit_time", glow_time ),
EUI_UINT8( "ui8", example_uint8 ),
EUI_UINT16( "i16", example_uint16 ),
EUI_UINT32( "i32", example_uint32 ),
EUI_FLOAT( "fPI", example_float ),
EUI_CHAR_ARRAY_RO( "name", demo_string ),
};
WiFiMulti WiFiMulti;
WebSocketsServer webSocket = WebSocketsServer(ws_port);
void tx_putc(uint8_t *data, uint16_t len);
void ws_tx_putc(uint8_t *data, uint16_t len);
eui_interface_t comm_links[] = {
EUI_INTERFACE(&tx_putc),
EUI_INTERFACE(&ws_tx_putc),
};
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length)
{
uint8_t * iter = payload;
uint8_t * end = payload + length;
switch(type)
{
case WStype_DISCONNECTED:
ws_connected = 2;
break;
case WStype_CONNECTED:
ws_connected = 3;
break;
case WStype_TEXT:
// send data to all connected clients
// webSocket.broadcastTXT("message here");
break;
case WStype_BIN:
while( iter < end )
{
eui_parse(*iter++, &comm_links[1]);
}
break;
case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT:
case WStype_FRAGMENT_FIN:
ws_connected = 4;
break;
}
}
void wifi_handle()
{
if( WiFiMulti.run() == WL_CONNECTED )
{
//we have a wifi connection
if(!ws_connected)
{
webSocket.begin();
webSocket.onEvent(webSocketEvent);
ws_connected = 1;
// The hint is formatted like ws://255.255.255.255:81
memset( ws_path, 0, sizeof(ws_path) ); //clear the string first
snprintf(ws_path, sizeof(ws_path), "ws://%s:%d", WiFi.localIP().toString().c_str(), ws_port);
glow_time = 200;
// Using Arduino Strings
// String ws_path_string = "ws://" + WiFi.localIP().toString().c_str() + ":" + String(ws_port);
// ws_path_string.toCharArray(ws_path, sizeof(ws_path));
}
else
{
webSocket.loop();
}
}
else
{
//no connection, try again later
ws_connected = 0;
}
}
void eui_callback( uint8_t message )
{
switch(message)
{
case EUI_CB_TRACKED:
// UI recieved a tracked message ID and has completed processing
break;
case EUI_CB_UNTRACKED:
{
// UI passed in an untracked message ID
// Grab parts of the inbound packet which are are useful
eui_header_t header = comm_links[0].packet.header;
uint8_t *name_rx = comm_links[0].packet.id_in;
void *payload = comm_links[0].packet.data_in;
// See if the inbound packet name matches our intended variable
if( strcmp( (char *)name_rx, "talk" ) == 0 )
{
webSocket.broadcastTXT("hello over websockets");
glow_time = 50;
}
}
break;
case EUI_CB_PARSE_FAIL:
break;
}
}
void setup()
{
Serial.begin(115200);
pinMode( LED_BUILTIN, OUTPUT );
//eUI setup
comm_links[0].interface_cb = &eui_callback;
eui_setup_interfaces(comm_links, 2);
EUI_TRACK(dev_msg_store);
eui_setup_identifier("esp32", 5);
WiFiMulti.addAP(wifi_ssid, wifi_pass);
led_timer = millis();
}
void loop()
{
wifi_handle();
while(Serial.available() > 0)
{
eui_parse(Serial.read(), &comm_links[0]);
}
if( blink_enable )
{
// Check if the LED has been on for the configured duration
if( millis() - led_timer >= glow_time )
{
led_state = !led_state; //invert led state
led_timer = millis();
}
}
digitalWrite( LED_PIN, led_state ); //update the LED to match the intended state
}
void tx_putc( uint8_t *data, uint16_t len )
{
Serial.write( data, len );
}
void ws_tx_putc( uint8_t *data, uint16_t len )
{
webSocket.broadcastBIN( data, len);
}
When I enter my SSID and Password the serial monitor just displays:
E (2462) wifi:Association refused temporarily, comeback time 200 mSec
However the LED is blinking as it should.... The Electric UI shows no devices found....

How to solve the deployment issue about QT creator?

I am going to deploy the QT creator project. But I discovered that some functions of deployment .exe are missing. However, it originally works inside the QT creator. I have no idea about how to solve the current problem, like using what tools to help. The missing function is that the program doesn't show the thumbnails about the video files, where I have assigned the relative images to that.
filemodel.h
#ifndef FILEMODEL_H
#define FILEMODEL_H
#include <QAbstractListModel>
#include <QDirIterator>
#include <QUrl>
#include <QMetaType>
#include <QFuture>
#include <QtConcurrent/QtConcurrent>
#include <iostream>
#include <QImage>
#include <iostream>
#include <fstream>
#include <string>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
struct File
{
Q_GADGET
Q_PROPERTY(QString name MEMBER name)
Q_PROPERTY(QUrl url MEMBER url)
Q_PROPERTY(QImage iconImg MEMBER iconImg)
Q_PROPERTY(QUrl urlicon MEMBER urlicon)
public:
QString name;
QUrl url;
QImage iconImg;
QUrl urlicon;
File(const QString& name=""){
//cout<<name.toStdString();
this->name = QFileInfo(name).fileName();
this->url = QUrl::fromLocalFile(name);
int i = name.toStdString().find(".mp4");
if(i<0)
{
this->urlicon = QUrl::fromLocalFile(name);
}
else{
string temp = QFileInfo(name).fileName().toStdString();
int j = temp.find(".mp4");
//string str = "C:\\Video\\"+ temp.replace(j,4,".jpg");
string str = "C:\\Video\\"+ temp.replace(j,4,".jpg");
this->urlicon = QUrl::fromLocalFile(QString::fromStdString(str));
}
}
};
Q_DECLARE_METATYPE(File)
class FileModel : public QAbstractListModel
{
enum dashBoardRoles {
NameRole=Qt::UserRole+1,
URLRole,
ICONRole,
URLICONRole
};
Q_OBJECT
Q_PROPERTY(QString folder READ folder WRITE setFolder NOTIFY folderChanged)
Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
public:
FileModel(QObject *parent=Q_NULLPTR):QAbstractListModel(parent){
}
Q_INVOKABLE QVariant get(int index){
return QVariant::fromValue(m_all_dirs[index]);
}
int rowCount(const QModelIndex &parent=QModelIndex()) const{
Q_UNUSED(parent)
return m_all_dirs.count();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const{
if(index.row()<0 && index.row()>= rowCount())
return QVariant();
File file = m_all_dirs[index.row()];
if(role == NameRole)
return file.name;
else if(role == URLRole)
return file.url;
else if(role == ICONRole)
return file.iconImg;
else if(role == URLICONRole)
return file.urlicon;
return QVariant();
}
QHash<int, QByteArray> roleNames() const {
QHash <int,QByteArray> roles;
roles [NameRole]="fileName";
roles [URLRole]="url";
roles [ICONRole]="icon";
roles [URLICONRole]="urlicon";
return roles;
}
QString folder() const{
return mFolder;
}
void setFolder(const QString &folder)
{
if(mFolder == folder)
return;
mFolder = folder;
emit folderChanged();
findFiles();
}
QStringList nameFilters() const{
return mNameFilters;
}
void setNameFilters(const QStringList &nameFilters){
if(mNameFilters == nameFilters)
return;
mNameFilters = nameFilters;
emit nameFiltersChanged();
findFiles();
}
signals:
void folderChanged();
void nameFiltersChanged();
private:
void findFiles(){
beginResetModel();
m_all_dirs.clear();
if(QDir(mFolder).exists()){
QFuture<QStringList> future = QtConcurrent::run([=]() {
QStringList files;
QDirIterator it(mFolder, mNameFilters, QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()){
files<<it.next();
}
ofstream myfile;
myfile.open (mFolder.toStdString()+"\\example.xml");
myfile <<"<files>"<<"\n";
for (int i = 0; i < files.size(); ++i)
myfile << "<"+ std::to_string(i) + ">"<< files.at(i).toStdString()<< "</"+ std::to_string(i) + ">" <<"\n";
//
myfile <<"</files>"<<"\n";
myfile.close();
for (int i = 0; i < files.size(); ++i){
int j = files.at(i).toStdString().find(".mp4");
if(j>0)
{
VideoCapture cap(files.at(i).toStdString());
Mat frame;
cap >> frame;
string str = QFileInfo(files.at(i)).fileName().toStdString();
int k = str.find(".mp4");
str = "C:\\Video\\"+ str.replace(k,4,".jpg");
imwrite(str,frame);
}
}
return files;
});
QStringList fullNames = future.result();
for(const QString& fullName: fullNames){
File file{fullName};
m_all_dirs << file;
}
//return 0;
}
endResetModel();
}
QString mFolder;
QList<File> m_all_dirs;
QStringList mNameFilters;
};
#endif // FILEMODEL_H
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "filemodel.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<FileModel>("com.contentplayermod.filemodel", 1,0, "FileModel");
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtMultimedia 5.8
import QtQuick.Layouts 1.3
import com.contentplayermod.filemodel 1.0
import QtQuick.Window 2.2
ApplicationWindow {
id:main_win
visible: true
width: 640
height: 480
title: qsTr("Tabs")
property int idx: 0
property bool isActive: true
Component.onCompleted: {
playTimer.start()
subWindow.show();
subWindow.requestActivate();
main_win.hide();
playMusic(grid_main.currentIndex)
}
GridView {
id:grid_main
anchors.fill: parent
cellWidth: 100; cellHeight: 100
focus: true
currentIndex: 0
model: FileModel{
id: myModel
folder: "c:\\test2"//"/mnt/sdcard/app_pictureFrameImage"//
nameFilters: ["*.jpg" ,"*.mp4"] //"*.mp4",
}
highlight: Rectangle { width: 80; height: 80; color: "lightsteelblue" }
delegate: Item {
width: 100; height: 100
Image {
id: myIcon
width: 30
height: 30
y: 20; anchors.horizontalCenter: parent.horizontalCenter
source: urlicon
}
Text {
anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter }
text: fileName
}
MouseArea {
anchors.fill: parent
onClicked: {
parent.GridView.view.currentIndex = index
}
}
}
Keys.onReturnPressed:{
playTimer.start()
subWindow.show();
subWindow.requestActivate();
playMusic(grid_main.currentIndex)
//subWindow.forceActiveFocus();
//event.accepted = true;
grid_main.focus = false;
}
/*
Keys.onPressed: {
if (event.key == 16777220) {//enter
playTimer.start()
subWindow.show();
subWindow.requestActivate();
playMusic(grid_main.currentIndex)
//subWindow.forceActiveFocus();
event.accepted = true;
grid_main.focus = false;
//main_win.hide();
}
}*/
}
Window {
id: subWindow
visible: true
width: 640
height: 480
MediaPlayer {
id: player
}
VideoOutput {
id: video
anchors.fill: parent
source: player
}
Item {
focus: true
Keys.onReturnPressed:{
subWindow.close()
grid_main.forceActiveFocus();
main_win.show();
}
}
}
function playMusic(index){
idx = index
//player.stop()
player.source = myModel.get(index).url
player.play()
}
Timer {
id: playTimer
interval: 2000
repeat: true
running: true
onTriggered: {
var source_name = player.source;
if(source_name.toString().indexOf(".jpg")>0 || source_name.toString().indexOf(".bmp")>0 || source_name.toString().indexOf(".png")>0){ //processing .jpg
if (idx + 1 < grid_main.count){
playMusic(idx + 1);
}else{
idx = 0;
playMusic(idx);
}
}
else if(source_name.toString().indexOf(".mp4")>0){ //processing .mp4
if (player.status == MediaPlayer.EndOfMedia){
if (idx + 1 < grid_main.count){
playMusic(idx + 1);
}else{
idx = 0;
playMusic(idx);
}
}
}
}
}
}

How many simultaneous/consecutive connections can an ESP8266 Webserver handle?

So I'm using the ESP8266WebServer and ESP8266WiFiMulti libraries to run a webpage with websockets and I'm trying to figure out how many client connections I can have, and if there's any way to increase that connection limit?
Right now it seems that I can successfully create three connections from separate IPs, and then upon initiating the fourth connection, it fails (the server doesn't crash in the serial model, but the fourth connection won't load the webpage).
I've also noticed that if I refresh my own singular connection a certain number of times (inconsistent), it will fail to load the webpage as well. I haven't been able to decipher whether this has to do with there being too many consecutive connections in general or if I'm overtaxing the server by attempting to reconnect within too quick a timeframe?
In general though, it seems rather unstable and I could really use some assistance on figuring out why.
Here's my current code:
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsServer.h>
#include <Hash.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
static const char ssid[] = "********";
static const char password[] = "********";
MDNSResponder mdns;
static void writeLED(bool);
ESP8266WiFiMulti WiFiMulti;
IPAddress ipAddressTest = (99,99,99,99);
ESP8266WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);
uint8_t pageHitCounter = 0;
IPAddress ipAddressOne = (99,99,99,99);
IPAddress ipAddressTwo = (99,99,99,99);
IPAddress ipAddressThree = (99,99,99,99);
IPAddress ipAddressFour = (99,99,99,99);
uint8_t rxBuff[256];
uint8_t som = 0x11;
uint8_t eom = 0x12;
uint8_t subsys;
uint8_t receivedSubsys;
uint8_t rx_byte = 0x00;
uint8_t messageLength = 0;
uint8_t receivedMessageLength = 0;
uint8_t messageContent;
uint8_t serialCurrent;
int initialCounter = 0;
boolean messageBegun = false;
boolean messageInProgress = false;
int currNumRefresh = 0;
int currMicroC = 0;
int currMicroD = 0;
int currMicroE = 0;
int currPressureC = 0;
int currPressureD = 0;
int currPressureE = 0;
int currValveStatusNumC = 0;
int currValveStatusNumD = 0;
int currValveStatusNumE = 0;
int currFluid = 0;
char statusbuf[256];
char status[] = "";
int statusIndex = 0;
String valveStatusC = "Closed";
String valveTubePropsC = "175px solid #00ADEF";
String valveColorC = "red";
String valveStatusD = "Closed";
String valveTubePropsD = "175px solid #00ADEF";
String valveColorD = "red";
String valveStatusE = "Closed";
String valveTubePropsE = "175px solid #00ADEF";
String valveColorE = "red";
uint8_t currCountdown = 0;
long prevTimeCountdown = 0;
long countdownInterval = 1000;
long countdownPostInterval = 100;
bool countdownFlag = true;
bool teensyPOWER = false;
bool pumpPOWER = false;
bool teensyLED = false;
void switchPOWERon() {
//Serial.println("TEST POWER ON");
int powerStatusLength = 1;
subsys = 0x10;
//Account for the end of message
messageLength = powerStatusLength + 2;
messageContent = 1;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
//Serial.println("");
//Serial.println("TURN POWER ON|");
//teensyLED = true;
} //end switchPOWERon
void switchPOWERoff() {
/*Very similar to switchPoweron(), removed for char space*/
} //end switchPOWERoff
void pumpPOWERon() {
//Serial.println("TEST POWER ON");
int pumpPowerStatusLength = 1;
subsys = 0x13;
//Account for the end of message
messageLength = pumpPowerStatusLength + 2;
messageContent = 1;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
//Serial.println("");
//Serial.println("TURN POWER ON|");
//teensyLED = true;
} //end switchPOWERon
void pumpPOWERoff() {
/*Very similar to pumpPoweron(), removed for char space*/
} //end switchPOWERoff
void switchLEDon() {
//Serial.println("TEST LED ON");
int ledStatusLength = 1;
subsys = 0x14;
//Account for the end of message
messageLength = ledStatusLength + 2;
messageContent = 1;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
//Serial.println("");
//Serial.println("TURN LED ON|");
//teensyLED = true;
} //end switchLEDon
void switchLEDoff() {
/*Very similar to switchLEDon(), removed for char space*/
} //end switchLEDoff
void statusUpdate(uint8_t num) {
//Valve C
if(currValveStatusNumC == 0)
{
valveColorC = "red";
valveTubePropsC = "175px solid #00ADEF";
valveStatusC = "Closed";
} //end if
else if(currValveStatusNumC == 1)
{
valveColorC = "green";
valveTubePropsC = "350px solid #00ADEF";
valveStatusC = "Open";
} //end else if
/*Valves D/E removed for char space, very similar to Valve C*/
String test = "";
test += currNumRefresh;
test += ",";
/*Preparing more variables to send to the webpage, removed for char space*/
test += ",";
test += ipAddressTest;
//Serial.print("TEST: ");
//Serial.println(ipAddressTest);
test.toCharArray(statusbuf, 256);
webSocket.sendTXT(num, statusbuf, strlen(statusbuf));
}
static const char PROGMEM INDEX_HTML[] = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<title>Adafruit HUZZAH ESP8266</title>
<style type='text/css'>
/*CSS removed to fit maximum number of allowed characters*/
</style>
<script>
var currPressureTest = 0;
var currFluidTest = 0;
function POWERswitch(){
var POWERswitchCheck = document.getElementById('switch1').checked;
if(POWERswitchCheck){
websock.send("teensyPOWERon");
}
else if(!POWERswitchCheck) {
websock.send("teensyPOWERoff");
}
}
function FLUSHbegin(){
websock.send("pumpPOWERon");
}
function FLUSHend(){
websock.send("pumpPOWERoff");
}
function LEDswitch(){
var LEDswitchCheck = document.getElementById('myonoffswitch').checked;
if(LEDswitchCheck){
websock.send("teensyLEDon");
}
else if(!LEDswitchCheck) {
websock.send("teensyLEDoff");
}
}
var websock;
var test = "open";
var webpageHitCounter = 20;
function start() {
websock = new WebSocket('ws://' + window.location.hostname + ':81/');
websock.onopen = function(evt) {
console.log('websock open');
statusUpdate();
};
websock.onclose = function(evt) {
console.log('websock close');
};
websock.onerror = function(evt) {
console.log(evt);
};
websock.onmessage = function(evt) {
console.log(evt);
var e = document.getElementById('ledstatus');
var te = document.getElementById('myonoffswitch');
var pe = document.getElementById('switch1');
if(evt.data === 'teensyPOWERon')
{
pe.checked = 'checked';
}
else if(evt.data === 'teensyPOWERoff')
{
pe.checked = '';
}
else if(evt.data === 'pumpPOWERon')
{
}
else if(evt.data === 'pumpPOWERoff')
{
}
else if(evt.data === 'teensyLEDon')
{
te.checked = 'checked';
}
else if(evt.data === 'teensyLEDoff')
{
te.checked = '';
}
else if(evt.data === 'Update Status')
{
}
else {
console.log('status event');
var totalStatus = evt.data;
var splitStatus = totalStatus.split(',');
//Num Refresh
document.getElementById("demo").innerHTML = splitStatus[0];
/*Setting more variables from splitStatus[], removed for char space*/
}
};
}
function statusUpdate() {
websock.send("Update Status");
setTimeout('statusUpdate()', 5000);
}
</script>
</head>
<body style='background-color:#4a4a4c;' onload="start();">
<div style='text-align:center;'>
<h1 style='text-decoration: underline; color:white;'>Adafruit HUZZAH ESP8266</h1>
</div>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<div style="clear:both;"></div>
<div class='counterContainer'>
<span id="counterText" style="color:white;"></span>
</div>
<div id='adminControls' class='adminControlsRow'>
<h2>Administrator Controls</h2>
<div id='Newbtn' class='powerSwitchContainer'>
<h2>HHIO PTT Power</h2>
<span class="switch">
<span class="switch-border1">
<span class="switch-border2">
<input id="switch1" type="checkbox" onclick='POWERswitch()' checked />
<label for="switch1"></label>
<span class="switch-top"></span>
<span class="switch-shadow"></span>
<span class="switch-handle"></span>
<span class="switch-handle-left"></span>
<span class="switch-handle-right"></span>
<span class="switch-handle-top"></span>
<span class="switch-handle-bottom"></span>
<span class="switch-handle-base"></span>
<span class="switch-led switch-led-green">
<span class="switch-led-border">
<span class="switch-led-light">
<span class="switch-led-glow"></span>
</span>
</span>
</span>
<span class="switch-led switch-led-red">
<span class="switch-led-border">
<span class="switch-led-light">
<span class="switch-led-glow"></span>
</span>
</span>
</span>
</span>
</span>
</span>
</div>
<div class='flushBtnContainer'>
<h2>Fluid Reservoir</h2>
<button id='flushBtn' onmousedown="FLUSHbegin();" onmouseup="FLUSHend();">Flush</button>
</div>
</div>
<div style='background-color:#1E1E20; clear:both;'>
<h2 style='color: white;'>LED Controls</h2>
<div id='LEDbtn' class='onoffswitch'>
<input type='checkbox' name='onoffswitch' class='onoffswitch-checkbox' id='myonoffswitch' onclick='LEDswitch()'>
<label class='onoffswitch-label' for='myonoffswitch'>
<span class='onoffswitch-inner'></span>
<span class='onoffswitch-switch'></span>
</label>
</div>
</div>
<div style='background-color:#1E1E20; color: white;'>
<h2>Num Refresh Test</h2>
<div id="demo"><h2>Let WEBSOCKET change this text</h2></div>
</div>
<div class='headerRow'>
/*Headers removed for char space*/
</div>
<div class='microswitchRow'>
<div class="microswitchContainer">
<div class="microswitch white">
<input type="radio" name="switchC" class="microswitchRadio" id="switchOffC" checked>
<input type="radio" name="switchC" class="microswitchRadio" id="switchOnC">
<label for="switchOffC">Detached</label>
<label for="switchOnC">Attached</label>
<span class="toggle"></span>
</div>
</div>
<div class="microswitchContainer">
<div class="microswitch white">
<input type="radio" name="switchD" class="microswitchRadio" id="switchOffD" checked>
<input type="radio" name="switchD" class="microswitchRadio" id="switchOnD">
<label for="switchOffD">Detached</label>
<label for="switchOnD">Attached</label>
<span class="toggle"></span>
</div>
</div>
<div class="microswitchContainer">
<div class="microswitch white">
<input type="radio" name="switchE" class="microswitchRadio" id="switchOffE" checked>
<input type="radio" name="switchE" class="microswitchRadio" id="switchOnE">
<label for="switchOffE">Detached</label>
<label for="switchOnE">Attached</label>
<span class="toggle"></span>
</div>
</div>
</div>
<div class='pressureRow'>
<div class='pressureContainer'>
<div class='gauge-a'></div>
<div class='gauge-b'></div>
<div class='gauge-c'></div>
<div class='gauge-data'><h1 id='pressurePercentC'>0%</h1></div>
</div>
<div class='pressureContainer'>
<div class='gauge-a'></div>
<div class='gauge-b'></div>
<div class='gauge-d'></div>
<div class='gauge-data'><h1 id='pressurePercentD'>0%</h1></div>
</div>
<div class='pressureContainer'>
<div class='gauge-a'></div>
<div class='gauge-b'></div>
<div class='gauge-e'></div>
<div class='gauge-data'><h1 id='pressurePercentE'>0%</h1></div>
</div>
</div>
<div class='valveRow'>
<div class='valveContainer'>
<div class="valveTube-c"></div>
<div class="valve-c"></div>
<div class='valve-data'><h1 id='valveStatus-c'>Closed</h1></div>
</div>
<div class='valveContainer'>
<div class="valveTube-d"></div>
<div class="valve-d"></div>
<div class='valve-data'><h1 id='valveStatus-d'>Closed</h1></div>
</div>
<div class='valveContainer'>
<div class="valveTube-e"></div>
<div class="valve-e"></div>
<div class='valve-data'><h1 id='valveStatus-e'>Closed</h1></div>
</div>
</div>
<div class='fluidContainer'>
<meter class='fluidMeter' max='100' value='50' low='25' high='75' optimum='100'></meter>
<div class='fluid-data'><h1 id='fluidPercent'>0%</h1></div>
</div>
</body>
</html>
)rawliteral";
const int LEDPIN = 0;
// Current POWER status
bool POWERStatus;
// Current LED status
bool LEDStatus;
// Commands sent through Web Socket
/*command array declarations removed for char space*/
const char statusIdentifier[] = "Update Status";
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length)
{
//Serial.printf("webSocketEvent(%d, %d, ...)\r\n", num, type);
switch(type) {
case WStype_DISCONNECTED:
//Serial.printf("[%u] Disconnected!\r\n", num);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
//Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\r\n", num, ip[0], ip[1], ip[2], ip[3], payload);
// Send the current LED status
if (LEDStatus) {
webSocket.sendTXT(num, LEDON, strlen(LEDON));
}
else if(!LEDStatus) {
webSocket.sendTXT(num, LEDOFF, strlen(LEDOFF));
}
else if(teensyPOWER) {
webSocket.sendTXT(num, teensyPOWERON, strlen(teensyPOWERON));
}
else if(!teensyPOWER) {
webSocket.sendTXT(num, teensyPOWEROFF, strlen(teensyPOWEROFF));
}
else if(pumpPOWER) {
webSocket.sendTXT(num, teensyPOWERON, strlen(teensyPOWERON));
}
else if(!pumpPOWER) {
webSocket.sendTXT(num, pumpPOWEROFF, strlen(pumpPOWEROFF));
}
else if(teensyLED) {
webSocket.sendTXT(num, teensyLEDON, strlen(teensyLEDON));
}
else if(!teensyLED) {
webSocket.sendTXT(num, teensyLEDOFF, strlen(teensyLEDOFF));
}
}
break;
case WStype_TEXT:
//Serial.printf("[%u] get Text: %s\r\n", num, payload);
if (strcmp(LEDON, (const char *)payload) == 0) {
writeLED(true);
}
else if (strcmp(LEDOFF, (const char *)payload) == 0) {
writeLED(false);
}
else if(strcmp(teensyPOWERON, (const char *)payload) == 0) {
switchPOWERon();
}
else if(strcmp(teensyPOWEROFF, (const char *)payload) == 0) {
switchPOWERoff();
}
else if(strcmp(pumpPOWERON, (const char *)payload) == 0) {
pumpPOWERon();
}
else if(strcmp(pumpPOWEROFF, (const char *)payload) == 0) {
pumpPOWERoff();
}
else if(strcmp(teensyLEDON, (const char *)payload) == 0) {
switchLEDon();
}
else if(strcmp(teensyLEDOFF, (const char *)payload) == 0) {
switchLEDoff();
}
else if(strcmp(statusIdentifier, (const char *)payload) == 0) {
statusUpdate(num);
}
else {
//Serial.println("Unknown command");
}
// send data to all connected clients
webSocket.broadcastTXT(payload, length);
break;
case WStype_BIN:
//Serial.printf("[%u] get binary length: %u\r\n", num, length);
hexdump(payload, length);
// echo data back to browser
webSocket.sendBIN(num, payload, length);
break;
default:
//Serial.printf("Invalid WStype [%d]\r\n", type);
break;
}
}
void handleRoot()
{
server.send(200, "text/html", INDEX_HTML);
if(ipAddressTest != (0,0,0,0))
{
if(ipAddressOne == (99,99,99,99))
{
ipAddressOne = ipAddressTest;
pageHitCounter++;
//server.send(200, "text/html", INDEX_HTML);
Serial.print("1st NEW IP: ");
Serial.println(ipAddressTest);
}
else if(ipAddressTwo == (99,99,99,99))
{
if(ipAddressOne == ipAddressTest)
{
Serial.print("Old Connection-1 currently connected; Current Connection: ");
Serial.println(ipAddressTest);
//server.send(200, "text/html", INDEX_HTML);
}
else
{
ipAddressTwo = ipAddressTest;
pageHitCounter++;
//server.send(200, "text/html", INDEX_HTML);
Serial.print("2nd NEW IP: ");
Serial.println(ipAddressTest);
}
}
else if(ipAddressThree == (99,99,99,99))
{
if(ipAddressOne == ipAddressTest || ipAddressTwo == ipAddressTest)
{
Serial.print("Old Connection-2 currently connected; Current Connection: ");
Serial.println(ipAddressTest);
//server.send(200, "text/html", INDEX_HTML);
}
else
{
ipAddressThree = ipAddressTest;
pageHitCounter++;
//server.send(200, "text/html", INDEX_HTML);
Serial.print("3rd NEW IP: ");
Serial.println(ipAddressTest);
}
}
else if(ipAddressFour == (99,99,99,99))
{
if(ipAddressOne == ipAddressTest || ipAddressTwo == ipAddressTest || ipAddressThree == ipAddressTest)
{
Serial.println("Old Connection-3 currently connected; Current Connection: ");
Serial.println(ipAddressTest);
//server.send(200, "text/html", INDEX_HTML);
}
else
{
ipAddressFour = ipAddressTest;
pageHitCounter++;
//server.send(200, "text/html", INDEX_HTML);
Serial.print("4th NEW IP: ");
Serial.println(ipAddressTest);
}
}
else
{
if(ipAddressOne == ipAddressTest || ipAddressTwo == ipAddressTest || ipAddressThree == ipAddressTest || ipAddressFour == ipAddressTest)
{
Serial.println("Old Connection-4 currently connected; Current Connection: ");
Serial.println(ipAddressTest);
//server.send(200, "text/html", INDEX_HTML);
}
else
{
Serial.print("Too many connections! Attempting to Connect: ");
Serial.println(ipAddressTest);
}
}
}
}
void handleNotFound()
{
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i=0; i<server.args(); i++){
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
static void writeLED(bool LEDon)
{
LEDStatus = LEDon;
// Note inverted logic for Adafruit HUZZAH board
if (LEDon) {
digitalWrite(LEDPIN, 0);
}
else {
digitalWrite(LEDPIN, 1);
}
}
void setup()
{
pinMode(LEDPIN, OUTPUT);
writeLED(false);
Serial.begin(115200);
//Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
currCountdown = 4;
for(uint8_t t = 4; t > 0; t--) {
unsigned long currTime = millis();
if(countdownFlag == true)
{
Serial.printf("[SETUP] BOOT WAIT %d...\r\n", t);
Serial.flush();
countdownFlag = false;
}
if(currTime - prevTimeCountdown > countdownInterval)
{
prevTimeCountdown = currTime;
countdownFlag = true;
} //end if
else
{
t++;
} //end else
} //end for
WiFiMulti.addAP(ssid, password);
/*
prevTimeCountdown = 0;
countdownFlag = true;
*/
while(WiFiMulti.run() != WL_CONNECTED) {
/*
unsigned long currTime = millis();
if(countdownFlag == true)
{
Serial.print(".");
countdownFlag = false;
} //end if
if(currTime - prevTimeCountdown > countdownInterval)
{
prevTimeCountdown = currTime;
countdownFlag = true;
} //end if
*/
Serial.print(".");
delay(1000);
} //end while
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (mdns.begin("espWebSock", WiFi.localIP())) {
Serial.println("MDNS responder started");
mdns.addService("http", "tcp", 80);
mdns.addService("ws", "tcp", 81);
}
else {
Serial.println("MDNS.begin failed");
}
Serial.print("Connect to http://espWebSock.local or http://");
Serial.println(WiFi.localIP());
server.on("/", handleRoot);
server.onNotFound(handleNotFound);
server.begin();
webSocket.begin();
webSocket.onEvent(webSocketEvent);
}
void loop()
{
//Communication Protocol
if(Serial.available() > 0)
{
//Serial.print("SERIAL.AVAILABLE: ");
//Serial.println(Serial.available());
if(initialCounter == 0)
{
rx_byte = Serial.read();
/*
//Print Start of Message
Serial.print("0x");
if(rx_byte<0x10)
{
Serial.print("0");
}
Serial.println(rx_byte, HEX);
*/
//Serial.println(rx_byte, BIN);
//Serial.println(rx_byte);
initialCounter++;
}
if((!messageBegun) && (rx_byte == som))
{
messageBegun = true;
//Serial.println("MESSAGE BEGUN TRUE");
} //end if (messageInProgress && rx_byte)
if((messageBegun) && (!messageInProgress))
{
serialCurrent = Serial.available();
if(serialCurrent > 0)
{
receivedMessageLength = (uint8_t)Serial.read();
/*
Serial.print("MESSAGE LENGTH: ");
Serial.println(receivedMessageLength);
*/
messageBegun = false;
messageInProgress = true;
//Serial.println("MESSAGE IN PROGRESS TRUE");
} //end if (serialCurrent)
} //end if (messageBegun && messageInProgress)
if(messageInProgress)
{
serialCurrent = Serial.available();
if(serialCurrent >= receivedMessageLength)
{
Serial.readBytes(rxBuff, receivedMessageLength);
if((byte)rxBuff[receivedMessageLength-1] != eom)
{
//Serial.println("ERROR");
//Serial.write(Serial.read());
} //end if (rxBuff != eom)
else
{
messageInProgress = false;
for(int i=0; i<receivedMessageLength; i++)
{
if(rxBuff[i] == eom)
{
/*
//Print End of Message
Serial.print("0x");
if(rx_byte<0x10)
{
Serial.print("0");
}
Serial.println(rxBuff[i], HEX);
*/
initialCounter = 0;
receivedMessageLength = 0;
} //end if
else if(i == 0)
{
receivedSubsys = rxBuff[i];
/*
//Print Subsystem
Serial.print("0x");
if(rx_byte<0x10)
{
Serial.print("0");
}
Serial.println(rxBuff[i], HEX);
*/
} //end if
else
{
if(receivedSubsys == 0x14)
{
currNumRefresh = rxBuff[i];
} //end if
/*Other subsystems removed for char space*/
} //end else
} //end if (serialCurrent)
} //end if (messageInProgress)
} //end if (Serial.available)
webSocket.loop();
ipAddressTest = server.handleClient();
}
P.S. I slightly modified ESP8266WebServer.cpp's handleClient() function to return the current IP address in order to track individual users, however sometimes I get 0.0.0.0 as an IP address and I don't know why or how to tell if that IP is a new IP or not.
I think Espressif documentation suggests a max of 5 UDP/TCP connections, that's what everyone always mentions anyways. I'd look it up but I'm behind a firewall right now :)
You don't mention which environment you are using, but I'm guessing Arduino based.
I don't know why you hit a limit at 3 instead of 5, could it be you're using connections for other protocols? I'm not sure what the MDNS stuff does, so maybe something in that. Also your browser could possibly be opening more connections then you expect (debug with browser debug functionality, e.g. f12? on most).
As usual, minimizing your code to the smallest example will help, try just the webserver, and see if you get closer to 5 :)
you must be careful with the size of the files you upload with FS.h. depending on the size some problems are generated when generating the page
Alright so I seem to have solved the issue by using the FS.h library and having an actual filesystem with directories where I can have actual html/css/js files and what not. This seems to have solved the stability issues.

Style input placeholder with Sass for focused fields

I'm trying to style placeholders for input fields (for different browsers) in Sass 3.3.1, and want to change the opacity when the field is focused. I'm having a hard time combining the pseudo-class and pseudo-elements with the ampersand. The following gives a compilation error:
::-webkit-input-placeholder,
:-moz-placeholder,
::-moz-placeholder,
:-ms-input-placeholder{
... some default styling
:focus#{&}{
opacity: 0;
}
}
Can this be done?
Edit
This is the output I am looking for:
::-webkit-input-placeholder {
opacity: 1;
}
:-moz-placeholder{
opacity: 1;
}
::-moz-placeholder{
opacity: 1;
}
:-ms-input-placeholder{
opacity: 1;
}
:focus::-webkit-input-placeholder {
opacity: 0;
}
:focus:-moz-placeholder{
opacity: 0;
}
:focus::-moz-placeholder{
opacity: 0;
}
:focus:-ms-input-placeholder{
opacity: 0;
}
// Cross-browsers opacity: #include opacity(0.5);
#mixin opacity($opacity) {
opacity: $opacity;
$opacity-ie: $opacity * 100;
filter: alpha(opacity=$opacity-ie); //IE8
}
// Transitions for all: #include transition($transition);
$transition: all .3s ease;
#mixin transition($value) {
-webkit-transition: $value;
-moz-transition: $value;
-ms-transition: $value;
-o-transition: $value;
transition: $value;
}
// Input placeholder animation: #include placeholder { color: #000 }
#mixin placeholder {
&::-webkit-input-placeholder {
#content;
}
&:-moz-placeholder {
#content;
}
&::-moz-placeholder {
#content;
}
&:-ms-input-placeholder {
#content;
}
}
// How to use:
input {
text-overflow: ellipsis;
color: mediumseagreen;
#include placeholder {
color: cornflowerblue;
transition: $transition;
#include opacity(1);
}
&:focus {
#include placeholder {
#include opacity(0);
transition: $transition;
}
}
}
This is going to be the other way around, actually:
element:focus{
&::-webkit-input-placeholder,
&:-moz-placeholder,
&::-moz-placeholder,
&:-ms-input-placeholder{
opacity: 0;
}
}
Edit
I seem to have a problem combining them in my testing, but the following should work:
::-webkit-input-placeholder{
color: red;
&:focus{
color: blue;
}
}
On thing to note, though, is that this only works if they are separated out. You cannot combine multiple pseudo-selectors to one definition (like ::-webkit-input-placeholder, :-moz-input-placeholder{ /* this does not work in my testing */ }).
Update 2
Heres a quick SASS function I mocked up that will simplify the process:
#mixin input-placeholder($all:default){
#if $all == default {
$all : ("::-webkit-input-placeholder", ":-moz-placeholder","::-moz-placeholder",":-ms-input-placeholder");
}
#each $placeholder in $all {
#{unquote($placeholder)}{
#content;
}
}
}
You can use it by doing the following:
#include input-placeholder{
color: red;
&:focus {
color: blue;
}
}
This means you only have to write your code once. It will output all of them on individual lines and apply the same rules to them.
Solution from SASS Compass:
// Style the html5 input placeholder in browsers that support it.
//
// The styles for the input placeholder are passed as mixin content
// and the selector comes from the mixin's context.
//
// For example:
//
// #{elements-of-type(text-input)} {
// #include input-placeholder {
// color: #bfbfbf;
// font-style: italic;
// }
// }
//
// if you want to apply the placeholder styles to all elements supporting
// the `input-placeholder` pseudo class (beware of performance impacts):
//
// * {
// #include input-placeholder {
// color: #bfbfbf;
// font-style: italic;
// }
// }
#mixin input-placeholder {
#include with-each-prefix(css-placeholder, $input-placeholder-support-threshold) {
#if $current-prefix == -webkit {
&::-webkit-input-placeholder { #content; }
}
#elseif $current-prefix == -moz {
// for Firefox 19 and below
#if support-legacy-browser("firefox", "4", "19", $threshold: $input-placeholder-support-threshold) {
&:-moz-placeholder { #content; }
}
// for Firefox 20 and above
&::-moz-placeholder { #content; }
}
#elseif $current-prefix == -ms {
&:-ms-input-placeholder { #content; }
}
}
// This is not standardized yet so no official selector is generated.
}

Resources