Windows print to default thermal printer - python-3.x

I'm developing a program to a shop. The program needs to print the receipt of the order using a termal printer.
I discovered that the printer follows the ESC/POS standard and I found out that there is a package that helps me having an interface with the printer caled python-esc/pos. However, to print throught a USB connected printer, I need to know the Vendor ID and Product ID. I've discovered a way to find this for all the connected printers on the sistem using the following code:
import usb
def is_printer(dev):
if dev.bDeviceClass == 7:
return True
for cfg in dev:
if usb.util.find_descriptor(cfg, bInterfaceClass=7) is not None:
return True
for printer in usb.core.find(find_all=True, custom_match = is_printer):
print('Decimal VendorID=' + str(printer.idVendor) + ' & ProductID=' + str(printer.idProduct) + '\n')
print('Hexadecimal VendorID=' + hex(printer.idVendor) + ' & ProductID=' + hex(printer.idProduct) + '\n\n')
However, I discovered that my client has multiple printers connected to his system. I want to be able to always print to the default printer. I would appreciate any help doing that since there are not many docs about default termal printers and all that
Edit: I should clarify that I do not have a thermal printer with me, so I'm working on the dark here, just hoping that it works in his hands.

Related

Can't Send Command to BLE Device Philips Hue Bulb (Connection Drops)

I am trying to turn my bluetooth Hue bulb on/off and change brightness using my Raspberry Pi 4B. The bulb is on, and I have successfully connected to it using bluez. When I try to run 'char-write-req 0x0027 01' to turn it on, I get this message:
GLib-WARNING **: 22:53:34.807: Invalid file descriptor
I can see that the connection is successful, but whenever I try to write a value to it, I just get this message and it disconnects. Running bluetoothctl 5.50. I have seen the patch conversation here: https://www.spinics.net/lists/linux-bluetooth/msg67617.html. But I am not sure it applies and I also wouldn't even know how to apply it. Can someone please help me!
EDIT I ditched the gatttool and am using bluetoothctl to connect to the bulb and menu gatt to send commands to it.
I figured out that the characteristic for toggling the light on and off is 932c32bd-0002-47a2-835a-a8d455b859dd (For my Philips Hue A19). After connecting to the bulb, I was able to select this attribute and use 'write 01' to turn it on and 'write 00' to turn it off.
The brightness characteristic is 932c32bd-0002-47a2-835a-a8d455b859dd. When I read, it outputs 'fe', which is HEX for 254. This is the highest brightness setting, which it was already set to. I can use 'write ' where value ranges from 1-254 to change the brightness.
Using acquire-write in bluetoothctl is typically not the correct command. read and write are what you want.
After starting starting bluetoothctl I would expect the series of commands to be:
connect <Address of bulb>
menu gatt
select-attribute 932c32bd-0002-47a2-835a-a8d455b859dd
write 1
write 0
If you wanted to script this, then below is a Python3 script that I would expect to turn the bulb on then off.
from time import sleep
from pydbus import SystemBus
BLUEZ_SERVICE = 'org.bluez'
BLUEZ_DEV_IFACE = 'org.bluez.Device1'
BLUEZ_CHR_IFACE = 'org.bluez.GattCharacteristic1'
class Central:
def __init__(self, address):
self.bus = SystemBus()
self.mngr = self.bus.get(BLUEZ_SERVICE, '/')
self.dev_path = self._from_device_address(address)
self.device = self.bus.get(BLUEZ_SERVICE, self.dev_path)
self.chars = {}
def _from_device_address(self, addr):
"""Look up D-Bus object path from device address"""
mng_objs = self.mngr.GetManagedObjects()
for path in mng_objs:
dev_addr = mng_objs[path].get(BLUEZ_DEV_IFACE, {}).get('Address', '')
if addr.casefold() == dev_addr.casefold():
return path
def _get_device_chars(self):
mng_objs = self.mngr.GetManagedObjects()
for path in mng_objs:
chr_uuid = mng_objs[path].get(BLUEZ_CHR_IFACE, {}).get('UUID')
if path.startswith(self.dev_path) and chr_uuid:
self.chars[chr_uuid] = self.bus.get(BLUEZ_SERVICE, path)
def connect(self):
"""
Connect to device.
Wait for GATT services to be resolved before returning
"""
self.device.Connect()
while not self.device.ServicesResolved:
sleep(0.5)
self._get_device_chars()
def disconnect(self):
"""Disconnect from device"""
self.device.Disconnect()
def char_write(self, uuid, value):
"""Write value to given GATT characteristic UUID"""
if uuid.casefold() in self.chars:
self.chars[uuid.casefold()].WriteValue(value, {})
else:
raise KeyError(f'UUID {uuid} not found')
def char_read(self, uuid):
"""Read value of given GATT characteristic UUID"""
if uuid.casefold() in self.chars:
return self.chars[uuid.casefold()].ReadValue({})
else:
raise KeyError(f'UUID {uuid} not found')
device_address = '11:22:33:44:55:66'
light_state = '932c32bd-0002-47a2-835a-a8d455b859dd'
dev = Central(device_address )
dev.connect()
dev.char_write(light_state , [1])
sleep(5)
dev.char_write(light_state , [0])
print(dev.char_read(light_state ))
dev.disconnect()
As I don't have a bulb the above is untested. But should be a good outline of what is required.
It worked for me after I reset the Bulb with the bluetooth app to factory settings.
The bulb appears to be able to be paired/bonded to a single device only. If other devices try to communicate with the bulb, the connection is lost, as #ukBaz mentioned in his comment.

Epson ESCPOS print Danish character using ESC R n command

I am using an Epson TM-T20II thermal receipt printer, and I need to print receipt out with Danish characters (æ,ø,å). To ESCPOS code for character language selection is described here. My Python code is as below
import win32print
import six
#create some raw data
rawdata = b'\x1b\x40' #Instantiate the printer ESC #
rawdata = rawdata + b'\x1b\x52\x10' #Select the Danish II character set as in documentation ESC R
where n = 10
rawdata = bytes('Print æ,ø,å', 'utf-8') + b'\n' + b'\x1d\x56' + six.int2byte(66) + b'\x00' #print
some text and cut
#Creating the printing job in Windows 10 and send the raw text to the printer driver
printer = win32print.OpenPrinter('EPSON TM-T20II Receipt')
hJob = win32print.StartDocPrinter(printer, 1, ("Test print", None, "RAW"))
win32print.WritePrinter(printer, rawdata)
win32print.EndPagePrinter(printer)
win32print.ClosePrinter(printer)
My problem is that I get some strange character printed out. Also I have set the printer to Danish II by holding down the feed button and while power on the printer. What have I missed?
For the time being, what you might want to try is to change the encoding specification below from utf-8 to cp865.
rawdata = bytes('Print æ,ø,å', 'utf-8') + b'\n' + b'\x1d\x56' + six.int2byte(66) + b'\x00' #print
If that doesn't work, you should stop using win32print and switch to pyserial.
It is also necessary to switch the printer mode, uninstall the Advanced Printer Driver, and install the printer serial port driver.
Then the application program needs to create all the print data using the raw ESC/POS commands.
The reason is as follows.
You can get the Advanced Printer Driver of TM-T20II and manual & sample program here.
EPSON Advanced Printer Driver for TM-T20II
According to the sample program "Step 1 Printing Device Font", in order to send a raw ESC/POS command to the printer, it is necessary to select a specific device font.
Prints "Hello APD" with a device font and autocuts a receipt.
The core of the sample source in C ++ is as follows.
CDC dc;
/*
* Create the device context for the printer
*/
if(! dc.CreateDC(EPS_DRIVER_NAME, EPS_PRINTER_NAME, NULL, NULL) )
{
AfxMessageBox(_T("Printer is not available."));
return;
}
dc.StartDoc(&di);
/*
* Perform the printing of the text
*/
CFont font, *old;
font.CreatePointFont(95, "FontA11", &dc);
old = dc.SelectObject(&font);
dc.TextOut(20, 10, "Hello APD!");
dc.SelectObject(old);
font.DeleteObject();
dc.EndPage();
dc.EndDoc();
dc.DeleteDC();
Here's what it looks like in VB.
Dim printFont As New Font("Lucida Console", 8, FontStyle.Regular, GraphicsUnit.Point) ' Substituted to FontA Font
e.Graphics.PageUnit = GraphicsUnit.Point
' Print the string at 6,4 location using FontA font.
e.Graphics.DrawString("Hello APD!", printFont, Brushes.Black, 6, 4)
' Indicate that no more data to print, and the Print Document can now send the print data to the spooler.
e.HasMorePages = False
Isn't it very difficult or impossible to port these to Python's win32print?
The win32print API doesn't seem to have the ability to customize fonts in the middle of printing.
Module win32print
And StartDocPrinter and WritePrinter have the following explanation.
win32print.StartDocPrinter
Note that the printer driver might ignore the requested data type.
win32print.WritePrinter
Suitable for copying raw Postscript or HPGL files to a printer.
The ESC/POS command is not raw PostScript or HPGL, and EPSON's Advanced Printer Driver does not necessarily send such data with a win32print call.

Creating an access point with wpa_supplicant via dbus interface

I was told that it's possible to create an access point with wpa_supplicant over its dbus interface. All I found with a google is this forum thread, which, despite having exact same title, isn't much informative to me.
Is it possible to do this via wpa_supplicant dbus interface and what exact steps does it take to create one with custom parameters (like frequency, etc.)?
After all, I've found a way to launch access point with wpa_supplicant's dbus inteface. Below is pretty self explanatory python code that's is trying to launch AP with the first interface (adapter) it have found.
import dbus
import sys
ssid = "TEST_WPA_DBUS_HOTSPOT"
frequency = 2412
bus = dbus.SystemBus()
wpa_sup_obj = bus.get_object('fi.w1.wpa_supplicant1', '/fi/w1/wpa_supplicant1')
props_iface = dbus.Interface(wpa_sup_obj, "org.freedesktop.DBus.Properties")
interfaces = props_iface.Get('fi.w1.wpa_supplicant1', "Interfaces")
try:
interface = interfaces[0]
except IndexError:
sys.exit("No interfaces availible")
print "Creating ap with %s" % (interface)
interface_obj = bus.get_object('fi.w1.wpa_supplicant1', interface)
interface_interface_props = dbus.Interface(interface_obj, "org.freedesktop.DBus.Properties")
interface_interface = dbus.Interface(interface_obj, "fi.w1.wpa_supplicant1.Interface")
adapters_name = interface_interface_props.Get("fi.w1.wpa_supplicant1.Interface", "Ifname")
print "Interface's name is %s" % adapters_name
key_mgmt = "NONE"
args = dbus.Dictionary({
'ssid': ssid,
'key_mgmt': key_mgmt,
'mode': 2,
'frequency': frequency
}, signature='sv')
netw = interface_interface.AddNetwork(args)
interface_interface.SelectNetwork(netw)
print "AP %s with frequency %i created with adapter %s" % ( ssid, frequency, adapters_name)
Note, that, after all, I've found wpa_supplicant not quite reliable for my needs (in my particular case, I wasn't able to launch 5GHz AP) and have switched to launching hostapd with different configuration files.

Obtain bluetooth signal strength on Raspberry Pi of BT device without pairing

I like to create a kind of indoor-tracking-system for my already existing home automation system. I thought of using BLE. I already successfully set up hcitool on my Raspberry Pi and I can connect to my iPhone without any problems. But how can I obtain the signal strength between my Raspberry Pi and my iPhone without connecting them. I already tried to use sudo hcitool cc [BTADDRESS] to connect to my iPhone without authentication, but it looks like the iPhone don't allow those connection to stay open. I think that must be a way to get the signal strength without connecting both devices. I want to use it to determine the distance from my Raspberry Pi to my iPhone. May I am able to calculate the distance from the time I need to discover my iPhone?
There are two ways to go, and by now I have been able to get both work reliably only on Android devices.
Exploiting the Bluetooth friendly name of the smartphone and set the discoverability to infinite. I have done this writing a simple app. Works in background, also after that the app has been killed, since the discoverability setting is preserved. At the best of my knowledge, this is not possible in iOS.
Advertising a UUID in a BLE packet from the phone. This can be done by both Android and iOS devices. However, while in background, iPhones switch the advertising to a shrinked mode that makes the packet unidentifiable. The problem of identifying an advertising iOS devices in background is still open.
On the raspberry, I used PyBluez to scan and looking for the presence of smartphones running (1) or (2). I report a code example:
import bluetooth
import bluetooth._bluetooth as bluez
import struct, socket, sys, select
def hci_enable_le_scan(sock):
hci_toggle_le_scan(sock, 0x01)
#Discover name and RSS of enabled BLE devices
class MyDiscoverer(bluetooth.DeviceDiscoverer):
def pre_inquiry(self):
self.done = False
def device_discovered(self, address, device_class, rssi, name):
discovery_logger.info("Discovered %s" % (address, ))
if name == "YOUR-DEVICE-FRIENDLY_NAME":
#Use the RSS for your detection / localization system
def inquiry_complete(self):
self.done = True
#Performs inquiry for name request
def async_inquiry():
d = MyDiscoverer()
while True:
d.find_devices(lookup_names = True)
readfiles = [ d, ]
while True:
rfds = select.select( readfiles, [], [] )[0]
if d in rfds:
d.process_event()
if d.done:
break
time.sleep(DISCOVERY_INTERVAL)
#Parse received advertising packets
def parse_events(sock):
# save current filter
old_filter = sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14)
flt = bluez.hci_filter_new()
bluez.hci_filter_all_events(flt)
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, flt )
while True:
pkt = sock.recv(255)
ptype, event, plen = struct.unpack("BBB", pkt[:3])
if event == LE_META_EVENT:
subevent, = struct.unpack("B", pkt[3])
pkt = pkt[4:]
if subevent == EVT_LE_CONN_COMPLETE:
le_handle_connection_complete(pkt)
elif subevent == EVT_LE_ADVERTISING_REPORT:
#Check if the advertisement is the one we are searching for
if getASCII(pkt[start:end]) == "YOUR-UUID"
report_pkt_offset = 0
report_data_length, = struct.unpack("B", pkt[report_pkt_offset + 9])
# each report is 2 (event type, bdaddr type) + 6 (the address)
# + 1 (data length field) + report_data length + 1 (rssi)
report_pkt_offset = report_pkt_offset + 10 + report_data_length + 1
rssi, = struct.unpack("b", pkt[report_pkt_offset -1])
#Now you have the RSS indicator, use it for monitoring / localization
sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, old_filter )
dev_id = 0
try:
sock = bluez.hci_open_dev(dev_id)
except:
print "error accessing bluetooth device..."
sys.exit(1)
p = threading.Thread(group=None, target=parse_events, name='parsing', args=(sock, ))
d = threading.Thread(group=None, target=async_inquiry, name='async_inquiry', args=())
try:
p.start()
except:
print "Error: unable to start parsing thread"
try:
d.start()
except:
print "Error: unable to start asynchronous discovery thread"

How to capture probe request data or probe response data sent from wireless router

I have a tplink-wr703n wireless router with OpenWrt.
I know I can capture all kinds of data when the adapter is in monitor mode.
I want to the adapter work in master mode, and I also want to capture probe request data sent from client or probe response data sent from my router.
I have tried to use libpcap to capture data, but I failed.
Can you tell me how I can get that data?
You can set up several modes on one radio card simultaneously.
Using the "iw" command you should be able to create a secondary wifi device interface with type monitor, I guess you could read all frame types from this one.
See http://wireless.kernel.org/en/users/Documentation/iw/vif/
I am also trying to prepare a scapy script to capture probe request only.
there is an Indian guy who made this nice video:https://www.youtube.com/watch?v=Z1MbpIkzQjU
His script seems to work in his enviroment but for some reason I cant get this to work for me.
I will appreciate your assistance.
The script is:
#!/usr/bin/python
import sys
from scapy.all import *
clientprobes = set()
def PacketHandler(pkt):
if pkt.haslayer(Dot11ProbeReq):
if len(pkt.info) > 0:
testcase = pkt.addr2 + '_ _ _' + pkt.info
if testcase not in clientprobes:
clientprobes.add(testcase)
print "New Probe Found: " + pkt.addr2 + ' ' + pkt.info
print "\n-----------Client Probes Table-------------\n"
counter = 1
for probe in clientprobes:
[client, ssid] = probe.split('---')
print counter, client, ssid
counter = counter + 1
print "\n--------------------------------------------\n"
sniff(iface = sys.argv[1], count = int(sys.argv[2]), prn = PacketHandler)

Resources