Создание тонкого клиента на базе дешевых одноплатных ПК

Иногда требуется сделать хитрый тонкий клиент — с необычной авторизацией и минимумом затрат.

Проще всего для этого использовать Linux.

Для одноплатных пк на базе ARM широко распространен дистрибутив Armbian, который основан на Debian ветке.

Для экспериментов у меня в наличии была плата OrangePi One
image
и MicroSD карта на 2G — я решил сделать из этого тонкий клиент RDP с окном блокировки и без лишнего программного обеспечения.

Дистрибутив Armbian для этой платы здесь.

Качаем последний с пометкой:

Server or light desktop usage scenarios.

В нем не будет рабочего стола, который не нужен в тонком клиенте.

Записываем образ на MicroSD (я использовал sourceforge.net/projects/win32diskimager).

После записи: вставляем MicroSD, подключаем все интерфейсы (LAN, Дисплей, клавиатуру, мышь), подаем питание, ждем пока загрузится.

Когда система загрузилась появится предложение ввести логин и пароль. Также можно зайти по SSH глянув выданный DHCP адрес (я воспользовался этой возможностью чтобы не вбивать настройки с клавиатуры и запустил PuTTY).

Логин: root
Пароль: 1234

После входа система попросит сменить пароль: вводим текущий 1234 и два раза новый пароль.

Также предлагается создать пользователя — назовем его user.

После этого приступим к настройке системы под задачу.

Установим недостающие пакеты:

apt update
apt install xorg lightdm xcursor-themes numix-gtk-theme numix-icon-theme 
apt install python-gtk2 freerdp

Запуск графического входа для systemd включется так:

systemctl set-default graphical.target

Создадим файлы:
(содать их проще всего с помощью редактора vi — после запуска с параметром нужно нажать i для вставки — потом просто вставить текст в окно консоли, а по завершении нажать Esc и набрать :w для записи и :q для выхода)

Для получения своих параметров через DHCP сервер

vi /etc/dhcp/dhclient-exit-hooks.d/paramscript

setup_add() {
    echo $new_host_name > /etc/hostname
    hostname $new_host_name

    if [ -z "$new_nds_servers" ] ; then
        echo $new_routers > /tmp/rdp_server
        echo "testuser" > /tmp/rdp_user
        echo "1234test#" > /tmp/rdp_passwd
    else
        echo $new_nds_servers > /tmp/rdp_server
        echo $new_nds_tree_name > /tmp/rdp_user
        echo $new_nds_context > /tmp/rdp_passwd
    fi
}

case $reason in
    BOUND|RENEW|REBIND|REBOOT)
        setup_add
        ;;
    EXPIRE|FAIL|RELEASE|STOP)
        return
        ;;
esac

этот скрипт получает по DHCP имя хоста и nds_servers, nds_tree_name, nds_context и сохраняет их значения в файлах во временной папке. По умолчанию будет использован IP адрес маршрутизатора.

Для настроек GTK и назначения его тем создадим

vi /home/user/.gtkrc-2.0

gtk-icon-theme-name = "Numix"
gtk-theme-name = "Numix"
gtk-cursor-theme-name = "whiteglass"

Для настройки менеджера графической среды LightDM:

vi /etc/lightdm/lightdm.conf

[LightDM]
greeter-user=user
[Seat:*]
greeter-session=my-greeter

я после экспериментов решил использовать greeter (программа входа), таким образом не придется настраивать автовход, а программа запустится от нужного пользователя.

Теперь создадим ярлык программы (и его папку):

mkdir /usr/share/xgreeters/
vi /usr/share/xgreeters/my-greeter.desktop

[Desktop Entry]
Name=PyGTK+ Greeter
Comment=This runs the PyGTK+ greeter, it should only be run from LightDM
Exec=python /home/user/greeter.py
Type=Application
X-Ubuntu-Gettext-Domain=lightdm

И сам код программы входа:

vi /home/user/greeter.py

Код предлагает ввести 4 значный пароль 0811 (месяц день с незначащими нулями без прбелов)
После успешного ввода запускается xfreerdp с полученными параметрами.

Код
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

from datetime import datetime
from gobject import timeout_add
import os,sys,gtk,pango,subprocess

class GreeterApp:
	def __init__( self ):
		self.builder = gtk.Builder()
		#self.builder.add_from_file("ui.glade")
		self.builder.add_from_string(ui)
		self.window = self.builder.get_object ("window")
		self.pass_field = self.builder.get_object ("pass_field")
		self.passct = self.builder.get_object ("pass")
		self.contrl = self.builder.get_object ("control")
		self.pass_field.modify_font(pango.FontDescription('Sans Bold 36'))
		self.passwd = datetime.now().strftime("%m%d")
		self.rdp_server = open("/tmp/rdp_server").read().split(',')[0]
		self.rdp_user = open("/tmp/rdp_user").read()
		self.rdp_passwd = open("/tmp/rdp_passwd").read()
		self.process = None
		timeout_add(5000, self.timeout)
		if self.window:
			self.window.connect("destroy", gtk.main_quit)
			self.contrl.set_visible(False)
			self.window.set_size_request(gtk.gdk.screen_width(),gtk.gdk.screen_height())
		self.builder.connect_signals(self)
	def hide(self, widget):
		self.contrl.set_visible(False)
		self.passct.set_visible(True)
		self.window.move(0,0)
		self.window.set_size_request(gtk.gdk.screen_width(),gtk.gdk.screen_height())
		if self.process:
			self.process.terminate()
			self.process = None
	def timeout(self):
		if self.window:
			self.window.set_keep_above(True)
			self.window.set_modal(True)
		return True
	def check_pass(self, widget):
		if self.pass_field.get_text() == self.passwd:
			self.pass_field.set_text("")
			self.passct.set_visible(False)
			self.contrl.set_visible(True)
			self.window.set_size_request(50,50)
			self.window.move(0,gtk.gdk.screen_height()-50)
			#sys.exit()
			self.process = subprocess.Popen(["xfreerdp","/v:"+self.rdp_server,"/f","/cert-ignore","/u:"+self.rdp_user,"/p:"+self.rdp_passwd])
	def clear_pass(self, widget):
		self.pass_field.set_text("")
	def num_press(self, widget):
		self.pass_field.set_text(self.pass_field.get_text()+widget.get_tooltip_text())
	def on_destroy(self, widget):
		sys.exit()
if __name__ == "__main__":
	settings = gtk.settings_get_default()
	#settings.props.gtk_button_images = True
	settings.props.gtk_enable_tooltips = False
	ui = """
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="2.24"/>
  <object class="GtkWindow" id="window">
    <property name="can_focus">False</property>
    <property name="type">popup</property>
    <property name="title" translatable="yes">MyGreeter</property>
    <property name="resizable">False</property>
    <signal name="destroy" handler="on_destroy" swapped="no"/>
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkHBox" id="control">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkButton" id="power1">
                <property name="use_action_appearance">False</property>
                <property name="width_request">50</property>
                <property name="height_request">42</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="hide" swapped="no"/>
                <child>
                  <object class="GtkImage" id="image4">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="stock">gtk-no</property>
                  </object>
                </child>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkHBox" id="hbox1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkTable" id="pass">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="n_rows">6</property>
                <property name="n_columns">3</property>
                <child>
                  <object class="GtkEntry" id="pass_field">
                    <property name="width_request">240</property>
                    <property name="height_request">60</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="visibility">False</property>
                    <property name="invisible_char">●</property>
                    <property name="xalign">1</property>
                    <property name="invisible_char_set">True</property>
                    <property name="primary_icon_activatable">False</property>
                    <property name="secondary_icon_activatable">False</property>
                    <property name="primary_icon_sensitive">True</property>
                    <property name="secondary_icon_sensitive">True</property>
                  </object>
                  <packing>
                    <property name="right_attach">3</property>
                    <property name="bottom_attach">2</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_0">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">0</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_0">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">0</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="top_attach">5</property>
                    <property name="bottom_attach">6</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_1">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">1</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_1">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">1</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="top_attach">4</property>
                    <property name="bottom_attach">5</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_2">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">2</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_2">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">2</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="right_attach">2</property>
                    <property name="top_attach">4</property>
                    <property name="bottom_attach">5</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_3">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">3</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_3">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">3</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="left_attach">2</property>
                    <property name="right_attach">3</property>
                    <property name="top_attach">4</property>
                    <property name="bottom_attach">5</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_4">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">4</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_4">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">4</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="top_attach">3</property>
                    <property name="bottom_attach">4</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_5">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">5</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_5">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">5</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="right_attach">2</property>
                    <property name="top_attach">3</property>
                    <property name="bottom_attach">4</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_6">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">6</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_6">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">6</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="left_attach">2</property>
                    <property name="right_attach">3</property>
                    <property name="top_attach">3</property>
                    <property name="bottom_attach">4</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_7">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">7</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_7">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">7</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="top_attach">2</property>
                    <property name="bottom_attach">3</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_8">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">8</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_8">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">8</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="right_attach">2</property>
                    <property name="top_attach">2</property>
                    <property name="bottom_attach">3</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_9">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">9</property>
                    <signal name="clicked" handler="num_press" swapped="no"/>
                    <child>
                      <object class="GtkLabel" id="l_9">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">9</property>
                        <attributes>
                          <attribute name="weight" value="bold"/>
                          <attribute name="size" value="40000"/>
                        </attributes>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="left_attach">2</property>
                    <property name="right_attach">3</property>
                    <property name="top_attach">2</property>
                    <property name="bottom_attach">3</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_ent">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <signal name="clicked" handler="check_pass" swapped="no"/>
                    <child>
                      <object class="GtkImage" id="image2">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="stock">gtk-yes</property>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="right_attach">2</property>
                    <property name="top_attach">5</property>
                    <property name="bottom_attach">6</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_del">
                    <property name="use_action_appearance">False</property>
                    <property name="width_request">80</property>
                    <property name="height_request">80</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <signal name="clicked" handler="clear_pass" swapped="no"/>
                    <child>
                      <object class="GtkImage" id="image3">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="stock">gtk-no</property>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="left_attach">2</property>
                    <property name="right_attach">3</property>
                    <property name="top_attach">5</property>
                    <property name="bottom_attach">6</property>
                    <property name="x_options">GTK_SHRINK</property>
                    <property name="y_options">GTK_SHRINK</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">False</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
	"""
	app = GreeterApp()
	app.window.show()
	gtk.main()


Код предоставлен как пример — можно сделать просто ввод имени и пароля для RDP подключения, выбор серверов, мониторинг серверов и все на что способна ваша фантазия — хоть вход по отпечатку пальца.

Комментарии 85

    0
    Немного жлобский вопрос: 1,2ГГц процессора и 512МБ памяти — это довольно много, 10 лет тому это был обычный офисный компьютер. Насколько часто сейчас на одноплатниках «толстые» рабочие места делают?
      +2
      Пробовал на raspberry-pi-3-model-b
      Firefox безбожно тормозит на половине сайтов. Либреофис тоже тормозит.
      Вспомнил времена 486 компьютеров и Windows 95, скорость не изменилась. Все медленно и печально.
        0
        Из бинарников ставили или пересобирали с -O3/Os? Браузеры (и тренды сайтостроительства) отдельная печальная тема.
          +2
          Готовый Raspbian with Desktop. Пользоваться десктопом можно, но только от полной безысходности.
          0

          Пользовался Orange Pi Plus 2E при переезде на другую работу 2 месяца до покупки компьютера. Подключался к офисному ПК. Всё отлично работало. Пользовался chromium. Даже FullHD фильмы смотрел. ОС Armbian, перенесенный во внутреннюю EMMC память. WI-FI встроенный все тянул нормально. Звук через колонки с питанием с него же по USB.


          Фото Orange Pi Plus 2E

          image


          Сейчас стоит на нем андроид + приложение HD VideoBox и висит над телевизором. Детям мультики смотреть самое то. Также ОС перенесена во внутреннюю память.


          Одно но: пассивный радиатор обязателен.

          +2
          Вполне юзабельно, если в качестве диска не использовать SD-карту.
          Тот же armbian позволяет «перенести» root на внешний диск, а с SD-карты грузить только ядро.
          А Raspberry Pi, начиная с третьей, вообще умеют загружаться с USB-storage, так что даже SD-карта не нужна.
            +1
            Raspberry Pi, начиная с третьей, вообще умеют загружаться с USB-storage

            Немаловажно, что Pi 3 получил загрузку по сети, а значит его можно использовать как тонкий клиент для LTSP-сервера. Без SD-карточек, без флешек. В 2015 году экспериментировал с Pi 1 B+ в качестве тонкого клиента для LTSP-сервера на базе Debian 7. Pi 1 B+ не умеет грузится по сети, поэтому приходилось велосипедить c Berryboot, а мощности процессора едва хватало для отрисовки картинки.
            0

            Ну так и требования изменились. Двадцать лет назад и двушка офис тянула вполне.
            С одноплатниками проблема с дровами. Особливо с видеодровами.

              +1
              Делают только под специализированное и оптимизированное ПО. Потому как обычное массовое и офисное ПО способно сожрать любое количество ресурсов без какой-либо практической пользы. :( Спасибо современному подходу к программированию, когда ради «hello world!» мы тащим 50 мегабайт библиотек на все случае жизни.
              0
              Пробовали freerdp не из репозиториев, а текущую версию с github? Проект довольно далеко уехал от версии 1.10
                0
                В конце надо флешку в RO сделать, динамические настройки в топку, на то они и динамические. Иначе флешка живёт не долго.
                  0
                  Похоже на байку. У меня в наличии 15 распберри на которых крутятся spring-boot демоны. За полтора года с железом проблем 0, логи пишутся, sd карты не мрут
                    0
                    Какая модель sd карточек?
                      0
                      Закупали комплекты «Малина» в Амперке. Они у них брендированные, выяснить фабрику затруднительно.
                      +3
                      у меня десятка два pi, raspbian. и больше сотни железок с openwrt, которые пишут данные на usb flash (буквально сотни килобайт в сутки).
                      что microsd, что usb дохнут.

                      переводим на ro + кольцевой буфер в NOR flash. иногда даже посещают мысли написать статью на хабр )
                      в таком применении я бы делал чисто ro
                      • НЛО прилетело и опубликовало эту надпись здесь
                          0
                          в куче сломанных есть и slc )
                          0
                          Было бы интересно почитать
                            0
                            А где вы нашли NOR flash который можно подключить к raspberry pi? И сколько он стоит примерно?
                              +2
                              обычно у NOR flash интерфейс SPI, так что подключить не проблема.
                              Мы используем флешку на 4 мегабайта, стоит порядка 100р.
                              Гигабайтных NOR не делают AFAIK, большие объёмы — вотчина NAND.
                              (зато у NOR 100к перезаписей и декларируется ненужность избыточного кодирования)
                                0
                                Спасибо за информацию, тогда всё хорошо действительно.
                                  0
                                  странно это все. wearleveling на контроллерах sd/usb флешек должен за счет объема обеспечить время жизни больше чем у 4МБ NOR. похоже на косяки с ФС или контроллером флешки (что маловероятно, учитывая что флешки были разные)
                                +3
                                Просим статью, очень просим. Несколько раз в разных областях нужна была инфа.
                                  +1
                                  может быть я не очень ясно выразился, речь была «как сделать защищённый от сбоев циклический буфер в флеш-памяти», вещь в общем-то далеко не новая, но готовых рецептов я не нагуглил.
                                  осложняется всё тем, что использовать можно лишь с некоторыми «железячными» навыками, ибо «из коробки» обычно нет доступной пользователю флеш-памяти.

                                  про r/o систему на sd/usb же — там всё просто, рецептов в сети очень много, хотя если есть интерес — то могу написать, как это получилось у меня
                                    0
                                    r/o система и так понятна. Используем. Но буффер — это интересно. Если не сложно, опишите пожалуйста в отдельном посте.
                                  0
                                  Конечно писать статью!
                                  Интересно будет многим!
                              0
                              Для LORA шлюзов использую NanoPi с eMMC + DietPi.
                              Прекрасно работают (без дисплея).
                                +1
                                WTWare же есть wtware.ru/index.html
                                  0
                                  Она для малинок внезапно стала платной. Хотя ожидаемо.
                                    0
                                    Если вся её платность сводится к появление надписи «Только для тестирования», то в чём проблема? У меня в своё время, когда я был сисадмином в отделе образования, лет пять крутилось около 30 таких машин.
                                  0
                                  Без принтера все теряет смысл.
                                    0
                                    Без локального принтера? Да вы, батенька, ретроград!
                                      +2
                                      Это не я, а наше правительство которое денег на оборудование не дает.
                                      В этом году попытаюсь списать Pentium III.
                                        0
                                        Сочувствую. Сам списывал лет 5 назад — но было проще, из блока питания во время работы вылетали искры))

                                        Тогда принтер в тот же хаб (он же надеюсь усб?) и настраивать уже самому — в условиях жесткой экономии, я думаю, труда не должно составить) Дальше либо расшарить и ловить терминальным сервером, либо если rdp-клиент умеет — пробрасывать в терминальную сессию.
                                          0

                                          Сцуко, случайно влупил минус, а переголосовать нельзя :(

                                            +3
                                            поправил :)
                                            0
                                            >> В этом году попытаюсь списать Pentium III.
                                            тогда можно использовать старый билд WTWare — и будет вам из Пня прекрасный тонкий клиент.
                                            Помню, у меня самый старый клиент был ПеньММХ с 2МБ ОЗУ — WTWare после загрузки по сети минуты три показывала чёрный экран пока процессор всё нужное обрабатывал. Зато потом всё летало как надо ;-)
                                          0

                                          А в чем проблема подключить принтер к одноплатнику? Например, у меня cubieboard2 спокойно принтсервером работает

                                            0
                                            LPT или COМ разъём?
                                              +2
                                              Вы из 2000 нам пишете?
                                                +1
                                                Из госучреждения. Это сильно меняет мировоззрение.
                                                  –3
                                                  Работать в гос учереждении — это ваш сознательный выбор. Как ориентация, фетиши и секс-игрушки. Но это не значит что тут все поголовно долбятся в бэкплейт. Так что смысла обсуждать эту область смысла нет.
                                                    +3
                                                    Проблема не в моей профессиональной ориентации, а в том, что самая частая проблема с подключением принтера — отсутствие соответствующего разъёма. А старого железа работает ещё очень много на просторах нашей необъятной родины.
                                                      +1

                                                      И работает хорошо, просто отлично, менять его на новое, которое внезапно ремонтировать дороже, заправлять без перепрошивки нельзя, и из плюсов у него только сетевой интерфейс — наверно могут лишь крупные компании

                                                        0
                                                        В крупных компаниях обычно к тому моменту успевают пол-механики сносить и не по разу.

                                                        Но подход гарантия кончилась — списываем — до сих пор вызывает муражки по коже…
                                                      0
                                                      кстати, ориентация- это не выбор.
                                                      0
                                                      >> Из госучреждения
                                                      >> LPT или COМ разъём
                                                      LPT без проблем перенаправляется как сетевой принтер, если правильно расшарить его. Причём можно даже расшарив подключать на этот самый компьютер — иногда по-другому в Win-среде использовать его не получается.
                                                      Самая «глубина» у меня в госучреждениях была — сделал сервер терминалов для DOS-овского 16-битного приложения (FoxPro 2.x) дя тонких клиентов, к каждому из которых был подключен LPT-принтер. Так что ничего невозможного нет.
                                                      +1
                                                      Может он счастливый обладатель epson lx 300. Определенная часть людей ищет эмуляторы такого принтера, чтобы получать данные с древнего оборудования в компьютере вместо бумаги.
                                                      Еще есть куча принтеров для печати на бланках и всяких этикетках, иногда они даже сейчас подключаются через COM.
                                                        +2
                                                        Ну предположим Com через usb работает уже в общем-то идеально.
                                                          0
                                                          >> Ну предположим Com через usb работает уже в общем-то идеально.
                                                          Далеко не всегда — как-то пробовал использовать такие переходники, ни разу не завелось. С DosPrn как-то проблем куда меньше.
                                                          0
                                                          Этот матричный разве не через usb? У меня таких несколько десятков. Там есть LPT, но я его не использую.
                                                            0
                                                            на сколько понял там usb появился далеко не в первой ревизии матери. мы к нему вообще мультиплексную линию прикручивали >_<
                                                              0
                                                              Lx300 lpt/com
                                                              Lx300+II USB/lpt/com
                                                              Lx350 полный аналог lx300(+II) по механике (спасибо эпсону что не стали поганить), также все интерфейсы скопом но зачем-то их перенесли с задней стенки в днище принтера, ближе к передней панели (иногда кабель коротковатым оказывается), дизайн посовременнее :)

                                                              Юзаю lx3xx полных ходом в сфере пассажирских перевозок, зверь машина :)
                                                        0
                                                        1) USB->COM/LPT (хз, не проверял как на LPT оно будет жить)
                                                        2) Если COM, то пардоньте, я ARMов без USART-а ещё не видел, MAX в роли преобразователя уровней и готово.
                                                        3) При желании LPT легко эмулируется на базе GPIO, вполне нормально себе выходило на Cortex-M0, правда в baremetal, в линуксе может какие-то грабли будут.

                                                        Для вариантов 2 и 3 наверное потребуется перестройка дерева устройств или колдунство с uboot-ом.
                                                          0
                                                          А если требуется полный СОМ? :)
                                                            0
                                                            В реалиях Cortex-M обычно пара портов бывает почти полноценных (нет RI), с Cortex-A я на фрискейле тоже обычно видел один порт с RTS/CTS(и оно даже работало), насчет DTE и прочих момедных сигналов не смотрел, нужды небыло.
                                                            0
                                                            1) На LPT жить будет лучше, он простой как грабли. А вот СОМ может потребоваться полный, т.е. не только RX/TX, а ещё CTS/RTS (чтобы в принтерах использовались ещё carrier detect и ring signal не помню) — тут уже не всякий преобразователь вывезет. Ещё бывает, когда пинами дёргают как попало, поперёк стандарта, этакий аналог GPIO, такое позволяют WinXP и более ранние, и такую содомию я даже видел.
                                                            2) Писать модуль ядра или работать поверх модуля gpio можно, но лениво.
                                                              0
                                                              Если идем USB->COM, то даже чертов пролифик умеет, не говоря об FTDI и CP21xx.
                                                              Если нам надо дёргать пинами вразнобой — то тогда уже идём в GPIO, т.к. умеет-ли мощный кортекс такое я хз.
                                                                0
                                                                У профилика большие проблемы с чётностью и двумя стопбитами.
                                                                0
                                                                USB-LPT как раз может быть проблема в некоторых режимах (ECP+DMA как минимум)
                                                                  0
                                                                  Нафига для LX-800 оно надо, сиё чудо и в SPP прекрасно живет
                                                                    0
                                                                    я к тому что не такой уж он и простой
                                                          0
                                                          Принтеры в орагизациях должны быть сетевые с поддержкой PCL5/6
                                                            0

                                                            по обоим пунктам можно поспорить.


                                                            1. сетевые принтеры таки дороже, расшаривание принтеров работает везде из коробки.
                                                              на «худых» системах можно использовать что-то вроде p910nd, есть опыт сборки для касс с tinycore, например, размер получившегося пакета — 8кб, единственный usb-принтер расшаривается вообще без каких-то дополнительных настроек, с печатью на него из windows/linux проблем тоже нет;
                                                            2. когда-то процессоры в принтерах были слабыми, памяти мало — печать ps была или тормозной, или глючной, или опция стоила дополнительных денег (а чаще несколько пунктов сразу). сейчас же я наблюдаю, что большинство принтеров у нас умеют ps (и используются именно как ps-принтеры).
                                                          +1
                                                          Смотрю на эту картинку и понимаю — нам срочно требуется mini(micro)-LAN port
                                                            +1
                                                            Чтобы патч-корды были в дифиците и стоили по 500 р. метр? Ненене Девид! А для тех, кому нужно потоньше есть wifi.
                                                              0
                                                              (уже отметили выше)
                                                              Для такой мелкой, пардон, фигнюльки, более уместным будет WiFi (который там, кстати, есть).
                                                              0
                                                              все бы хорошо но нет VGA и нет принтеров…
                                                                0
                                                                Принтер с терминального сервера всё равно использовать.
                                                                  0

                                                                  Есть же не сетевые принтеры, мало того есть так называемые wins принтеры, которые с принтсерверами не работают, вот с ними геморрой даже с одноплатниками, пример canon lbp2900, hp1005,1010,1018
                                                                  Сам хотел тонкий клиент собрать на одноплатнике, но вот canon 2900 завести и расшарить нормально не смог

                                                                  0

                                                                  Vga идеально было бы :( Но среди одноплатников встречается очень редко

                                                                    0
                                                                    cubieboard вроде имеет на GPIO, cubietruck вообще onboard. про остальные не скажу ничего
                                                                    0
                                                                    VGA можно сделать из HDMI, цена вопроса 500-2000р на радиорынке/компьютерном магазине.
                                                                      0
                                                                      цена переходника 70% от стоимости компьютера — многовато
                                                                        +1
                                                                        открою вам тайну — за 1000 руб я уже готовый компьютер с сетевухой купить могу который сам может грузиться с tftp в wtware и на этом все и заканчивается — работает все отработано все pgg полный вагон
                                                                        0
                                                                        Не знаю, как у этого, а для raspberry pi точно была нахлобучка с vga (грубо говоря, набор резисторов на пинах).
                                                                        0
                                                                        Just business, все выше перечисленное в цветной коробочке с магическими названиями крупных производителей доходит от 250 американских рублей.

                                                                        Может вам компанию создать по производству тонких клиентов?
                                                                        Тема то популярная и востребованная, во многих офисных делах это оптимальное решение, маленькая коробка присобаченная к монитору, клава и мышка, вот и весь набор.
                                                                          0

                                                                          На хабре есть компания, которая создавала такое решение на основе cubieboard. Открытый терминальный клиент.
                                                                          Видимо, не зашло у них, раз они не пишут ничего в блоге.


                                                                          Я покупал поиграться, хорошая штука, выручил терминал, когда основной компьютер сломался.

                                                                            0
                                                                            Однако.
                                                                            0

                                                                            Какой смысл данной статьи?
                                                                            Тут нет объяснения почему мы решили сразу взять одноплатник, и судя по всему автор купил и не знает что теперь с ним делать.
                                                                            А таких статей на просторах сети итак выше крыши.
                                                                            Спокойно можно тогда еще написать статью об использовании старого ноутбука как базу для тонкого клиента.

                                                                              0
                                                                              Тут суть как сделать кастомный вход в систему или автозапуск своего ПО.
                                                                              0
                                                                              Добавлю, что orange pi совершенно не надежные одноплатники. На руках 3 разные модели убитые статическим электричеством.
                                                                                0
                                                                                Orange Pi взят просто потому что был, согласен что они не надежные, зато дешовые.
                                                                                0
                                                                                Тонкий клиент на Распберри Пи, еще на первой версии делал в 2011 году. Работал исправно, для офиса хватало, правда сотрудники не любили его, игрушки нельзя, ютуб тормозил, и социальные сети мы обрубили… деспоты одним словом. А так, да решение, для офиса считаю отличную.
                                                                                По поводу толстой, 3-ю версию использую иногда даже на Ubuntu Mate. Работает сносно, ютуб даже работает, если только не полный экран. Для простого интернет серфинга, написать какой нибудь документ можно. Только не все сразу.

                                                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                Самое читаемое