Clicky

20210918

Wireless printer server for USB printers

Use case: your USB printer has no network interface or the network interface of the printer can not be used (e.g. no cabled network). Or you want to place the printer in the corner of your home office without a network cable or you want to improve the Women Acceptance Factor (WAF) of a printer in your living area.

In this post I am going to tell how to use OpenWRT firmware on a WiFi Access Point (WAP). The goal was simplicity, not a super fancy or secure solution. "First enable, then improve...!". Let's go!


1. Prerequisites. 

Collect the next data:

- IP address (subnet) of your home WiFi
- Home WiFi SSID and password

Have:
- A computer with wired network adapter and a network cable

2. Get yourself a WiFi Access Point (WAP). Look on the attic or on eBay. Check here to check if your WAP is capable of running OpenWRT and make sure that it has one (or more) USB port. Any USB port is OK. If you need more printers than available USB ports, you may use a USB hub to connect the printers to the print server. Make sure the WAP has at least 8MB Flash memory (dmesg | grep Kbytes or dmesg | grep KiB might tell)!

I have tested here a TP-Link TL-WR710N (v1.2), TP-Link Archer C7, D-Link DIR-505, Cisco/Linksys E4200 and TP-Link TL-WR1043ND. I got those for free or (less than) EUR10.

3. Connect a computer to ethernet port #1 or port LAN of the WAP. Install OpenWRT. The installation of OpenWRT to a WAP goes beyond this post because the installation might differ per used WAP. See here for OpenWRT install hints. You should land here:


4. IMPORTANT: In case the IP address of your home network devices start with 192.168.1.{any number}, you have to change the IP address of the WAP. Else goto 5.

From the OpenWRT start page, goto Network > Interfaces > LAN. And change the IPv4 address to 192.168.{any number between 2 and 254}.1. E.g. 192.168.2.1 . Leave all other settings as-is and press "Save & Apply".

 


5. Configure the WiFi adapter of the WAP as a WiFi client of your home network. From the start screen of OpenWRT, select "Network" > "Wireless". Select a network adapter and press the [Scan] button. From the resulting list, select your home WiFi SSID > "Join Network" and enter your WiFi password in the next screen. Select "Save" > "Save & Apply". 

Validation: Goto "Network" > "Wireless". The section "Associated Stations" should show the connection to your Home WiFi network. The computer that is connected to the WAP should have Internet access now.

 


6. Now that we have Internet access, we can install the p910n print server package. Use Putty or similar to connect to 192.168.1.1 (or the LAN IP addres you set in step #4) and open a command console. Issue the next commands in the console:

opkg install wget-ssl --no-check-certificate
opkg update

opkg install usbutils

opkg install kmod-usb-printer

opkg install p910nd luci-app-p910nd

#--- For D-Link DIR-505 uncomment the next line (USB driver)...

#opkg install kmod-usb-chipidea2

reboot

7. Configuring the print server. After the reboot reconnect goto "Services" > "p910nd - Printer server" and tick the box "Enable" > "Save & Apply." 

8. Configuring the firewall. Goto "Network" > "Firewall" > "Zones" > "Zone wan". Set "Input" & "Output" & "Forward" to "accept"


9. The WAP WiFi adapter needs to have a static address, so that computers that want to print to the printer server can find the print server. Goto "Network" > "Interfaces" > "WWAN" > "Protocol" > "Static Address". Change the "IPv4 Address" to an address in the range of your home network. Make sure you do not select and address in the DHCP range. You may try an IP address that ends on 240 to 249. E.g. 192.168.1.244. Set the Network mask to 255.255.255.0. Remember this IP address:

10. Now connect your printer(s) to the WAP and test the print server from a computer in your house, e.g. your desktop computer. 

Connect a printer (Windows):
        Win Key + S > Printers & Scanners > Add a Printer or Scanner > The printer that I want isn't listed > Add a printer usinga TCP/IP address or hostname. At "Hostname or IP address" > {IP Address of Step 9} (This step may take a minute) > Next. 

Select the printer drive for the UBS printer that is connected to the print server. Select all defaults in the next pages. Set printer properties in Windows (paper size etc.), and print a test page.


Testing from a PC in your home network:

    1. Test if the WAP is accessable:
    PING {IP address of step9}

     Should return succes.
    2. Test if the printer server is accessable:
        TELNET {IP address of step 9} 9100
  
Should return a black screen

Troubleshooting with the OpenWRT console:

Command: lsusb 

Should show USB devices and USB ports. Should list the name of the USB printer

Command: ls /dev/usb/lp*

Should list the number of "lp" ports that are in use. One per connected USB printer. E.g. 2 connected USB printers will show:  

/dev/usb/lp0 /dev/usb/lp1

Troubleshooting with Windows: see step 10   

20210406

ESP + NTP to DST

This ESP code pulls the date from NTP and calculates if today is DST. The DST algorithm is based on this post.

The output will look something like:

09:38:57.832 -> *** Connecting to SSID: {SSID}
09:38:57.832 -> ...
09:38:57.979 -> *** WiFi connected.
09:38:57.979 -> IP address: 192.168.x.111
09:38:58.032 -> DST: 1

//--- Libraries...
  //--- WiFi + NTP...
  #include <ESP8266WiFi.h>
  #include <NTPClient.h>
  #include <WiFiUdp.h> 

  //--- Date to epoch...
  #include <TimeLib.h>


//--- WiFi and network...
  const char* ssid     = "{SSID}";
  const char* password = "{password}";


//--- NTP...
  WiFiUDP ntpUDP;
  const int CETtoGMToffset = 3600; //--- Central European Time (CET) offset to GMT...
  NTPClient timeClient(ntpUDP"time.kriss.re.kr",CETtoGMToffset,60000);


//--- setup() ----------------------------------------------------------------------------
void setup(){
  

  Serial.begin(74880); //--- Prevent garbled output, show ESP8266 boot output...
  delay(500);
  Serial.println();


//--- Start WiFi...
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.println("*** Connecting to SSID: " + String(ssid));
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssidpassword);

  while (WiFi.status() != WL_CONNECTED) {

    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    Serial.print(".");
    delay(50);

  }

  digitalWrite(LED_BUILTIN,HIGH);
  Serial.println("\r\n*** WiFi connected.");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
//--- WiFi connection established...


// Initialize a NTPClient to get time from NTP server...
  timeClient.begin();

//--- Is today in DST?
  Serial.println("DST: " + String(nowInDST()));

}    


//--- loop() ----------------------------------------------------------------------------

void loop(){
    
}


boolean nowInDST()
{

  boolean isInDST = false;

  //--- Retrieve epoch from NTP server...  
  timeClient.update();  
  unsigned long epochTime = timeClient.getEpochTime();
  
  //--- Destil current year...  
  struct tm *ptm = gmtime ((time_t *)&epochTime); 
  int y = ptm->tm_year+1900;

  //--- Calculate epoch values for start and end of DST for this year...
  unsigned long firstDSTepoch = toEpoch(y,3lastSundayOfMonth(y,3) ,2,0,0); //--- Start of CET DST in epoch...
  unsigned long lastDSTepoch  = toEpoch(y,10,lastSundayOfMonth(y,10),2,0,0); //--- End of CET DST in epoch...

  //--- Check epoch if in DST...  
  if (epochTime >= firstDSTepoch && epochTime < lastDSTepoch
  {
    isInDST = true;
  }
  
  return isInDST;

}


//--- Calculate the date of the last Sunday in a given month...
int lastSundayOfMonth(int yint M)
{
  //--- Take care of leap years...
  int daysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
  if (y % 4  == 0 && y % 100 != 0) {daysInMonth[1= 29;}

  //--- Last day of month M to epoch...
  unsigned long epoch = toEpoch(y,M,daysInMonth[M-1],0,0,0);

  //--- Day of week, based on ISO8601...
  int dayOfWeek = ((epoch / 86400+ 4% 7;

  //--- Calculate date of last Sunday...
  int lastSundayOfMonth = daysInMonth[M-1- dayOfWeek;
  return lastSundayOfMonth;
  
}

//--- Converts a date to epoch (TimeLib.h)...
unsigned long toEpoch(int ybyte M , byte dbyte hbyte mbyte s)
{
  
  tmElements_t tmSet;
  tmSet.Year = y - 1970;
  tmSet.Month = M;
  tmSet.Day = d;
  tmSet.Hour = h;
  tmSet.Minute = m;
  tmSet.Second = s;
  return makeTime(tmSet);
  
}

20210402

Arduino/ESP function: inEuropeanDST

There are many other, most likely better, functions to calculate if a given date/time is in European Daylight Saving Time. But the function below is simpler to understand because most calculations are done in-line. Only the "toEpoch" function is used from the "TimeLib.h" library.

This function calculates the epoch at 2AM of the last Sunday of March (start of EU DST) and the epoch at 2AM on the last Sunday of October (end of EU DST) and checks if the given date is in between (summertime) or not (wintertime).

#include <TimeLib.h>

void setup()
{
  Serial.begin(74880);
  delay(1000);
  Serial.println();

  //--- Begin of EU DST in 2021...
  Serial.println(inDST(2021,3,28,1,59,59));
  Serial.println(inDST(2021,3,28,2,0,0));

  //--- End of EU DST in 2021...
  Serial.println(inDST(2021,10,31,1,59,59));
  Serial.println(inDST(2021,10,31,2,0,0));
  
}

void loop()
{
}

boolean inDST(int yint Mint dint hint mint s)
{

  boolean isInDST = false;
  
  unsigned long parsedDate    = toEpoch(yMdhms);                   //--- Parsed date to epoch...
  unsigned long firstDSTepoch = toEpoch(y,3lastSundayOfMonth(y,3) ,2,0,0); //--- Start of DST in epoch...
  unsigned long lastDSTepoch  = toEpoch(y,10,lastSundayOfMonth(y,10),2,0,0); //--- End of DST in epoch...
  
  if (parsedDate >= firstDSTepoch && parsedDate < lastDSTepoch
  {
    isInDST = true;
  }
  
  return isInDST;

}


//--- Calculate the day of the last Sunday of a given month...
int lastSundayOfMonth(int yint M)
{
  //--- Take care of leap years...
  int daysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
  if (y % 4  == 0 && y % 100 != 0) {daysInMonth[1= 29;}

  //--- Last day of month M to epoch...
  unsigned long epoch = toEpoch(y,M,daysInMonth[M-1],0,0,0);

  //--- Day of week, based on ISO8601...
  int dayOfWeek = ((epoch / 86400+ 4% 7;

  //--- Calculate date of last Sunday...
  return (daysInMonth[M-1- dayOfWeek);
  
}

//--- Converts a date to epoch (TimeLib.h)...
unsigned long toEpoch(int ybyte M , byte dbyte hbyte mbyte s)
{
  
  tmElements_t tmSet;
  tmSet.Year = y - 1970;
  tmSet.Month = M;
  tmSet.Day = d;
  tmSet.Hour = h;
  tmSet.Minute = m;
  tmSet.Second = s;
  return makeTime(tmSet);
  
}

 The output shows the second before and after the change to/from DST in 2021:

07:16:31.652 ->
07:16:31.652 ->  ets Jan  8 2013,rst cause:2, boot mode:(3,6)
07:16:31.652 ->
07:16:31.652 -> load 0x4010f000, len 3584, room 16
07:16:31.652 -> tail 0
07:16:31.652 -> chksum 0xb0
07:16:31.652 -> csum 0xb0
07:16:31.652 -> v2843a5ac
07:16:31.652 -> ~ld
07:16:32.755 ->
07:16:32.755 -> 0
07:16:32.755 -> 1
07:16:32.755 -> 1
07:16:32.755 -> 0







Real Time Web Analytics